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 || mPipelineWatcher.lock()->pipelineFull()) {
622         return;
623     }
624     {
625         Mutexed<Output>::Locked output(mOutput);
626         if (!output->buffers ||
627                 output->buffers->hasPending() ||
628                 output->buffers->numClientBuffers() >= output->numSlots) {
629             return;
630         }
631     }
632     size_t numInputSlots = mInput.lock()->numSlots;
633     for (size_t i = 0; i < numInputSlots; ++i) {
634         sp<MediaCodecBuffer> inBuffer;
635         size_t index;
636         {
637             Mutexed<Input>::Locked input(mInput);
638             if (input->buffers->numClientBuffers() >= input->numSlots) {
639                 return;
640             }
641             if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
642                 ALOGV("[%s] no new buffer available", mName);
643                 break;
644             }
645         }
646         ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
647         mCallback->onInputBufferAvailable(index, inBuffer);
648     }
649 }
650 
renderOutputBuffer(const sp<MediaCodecBuffer> & buffer,int64_t timestampNs)651 status_t CCodecBufferChannel::renderOutputBuffer(
652         const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
653     ALOGV("[%s] renderOutputBuffer: %p", mName, buffer.get());
654     std::shared_ptr<C2Buffer> c2Buffer;
655     bool released = false;
656     {
657         Mutexed<Output>::Locked output(mOutput);
658         if (output->buffers) {
659             released = output->buffers->releaseBuffer(buffer, &c2Buffer);
660         }
661     }
662     // NOTE: some apps try to releaseOutputBuffer() with timestamp and/or render
663     //       set to true.
664     sendOutputBuffers();
665     // input buffer feeding may have been gated by pending output buffers
666     feedInputBufferIfAvailable();
667     if (!c2Buffer) {
668         if (released) {
669             std::call_once(mRenderWarningFlag, [this] {
670                 ALOGW("[%s] The app is calling releaseOutputBuffer() with "
671                       "timestamp or render=true with non-video buffers. Apps should "
672                       "call releaseOutputBuffer() with render=false for those.",
673                       mName);
674             });
675         }
676         return INVALID_OPERATION;
677     }
678 
679 #if 0
680     const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info();
681     ALOGV("[%s] queuing gfx buffer with %zu infos", mName, infoParams.size());
682     for (const std::shared_ptr<const C2Info> &info : infoParams) {
683         AString res;
684         for (size_t ix = 0; ix + 3 < info->size(); ix += 4) {
685             if (ix) res.append(", ");
686             res.append(*((int32_t*)info.get() + (ix / 4)));
687         }
688         ALOGV("  [%s]", res.c_str());
689     }
690 #endif
691     std::shared_ptr<const C2StreamRotationInfo::output> rotation =
692         std::static_pointer_cast<const C2StreamRotationInfo::output>(
693                 c2Buffer->getInfo(C2StreamRotationInfo::output::PARAM_TYPE));
694     bool flip = rotation && (rotation->flip & 1);
695     uint32_t quarters = ((rotation ? rotation->value : 0) / 90) & 3;
696     uint32_t transform = 0;
697     switch (quarters) {
698         case 0: // no rotation
699             transform = flip ? HAL_TRANSFORM_FLIP_H : 0;
700             break;
701         case 1: // 90 degrees counter-clockwise
702             transform = flip ? (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90)
703                     : HAL_TRANSFORM_ROT_270;
704             break;
705         case 2: // 180 degrees
706             transform = flip ? HAL_TRANSFORM_FLIP_V : HAL_TRANSFORM_ROT_180;
707             break;
708         case 3: // 90 degrees clockwise
709             transform = flip ? (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90)
710                     : HAL_TRANSFORM_ROT_90;
711             break;
712     }
713 
714     std::shared_ptr<const C2StreamSurfaceScalingInfo::output> surfaceScaling =
715         std::static_pointer_cast<const C2StreamSurfaceScalingInfo::output>(
716                 c2Buffer->getInfo(C2StreamSurfaceScalingInfo::output::PARAM_TYPE));
717     uint32_t videoScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
718     if (surfaceScaling) {
719         videoScalingMode = surfaceScaling->value;
720     }
721 
722     // Use dataspace from format as it has the default aspects already applied
723     android_dataspace_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
724     (void)buffer->format()->findInt32("android._dataspace", (int32_t *)&dataSpace);
725 
726     // HDR static info
727     std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo =
728         std::static_pointer_cast<const C2StreamHdrStaticInfo::output>(
729                 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE));
730 
731     // HDR10 plus info
732     std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
733         std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
734                 c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
735     if (hdr10PlusInfo && hdr10PlusInfo->flexCount() == 0) {
736         hdr10PlusInfo.reset();
737     }
738 
739     {
740         Mutexed<OutputSurface>::Locked output(mOutputSurface);
741         if (output->surface == nullptr) {
742             ALOGI("[%s] cannot render buffer without surface", mName);
743             return OK;
744         }
745     }
746 
747     std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
748     if (blocks.size() != 1u) {
749         ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
750         return UNKNOWN_ERROR;
751     }
752     const C2ConstGraphicBlock &block = blocks.front();
753 
754     // TODO: revisit this after C2Fence implementation.
755     android::IGraphicBufferProducer::QueueBufferInput qbi(
756             timestampNs,
757             false, // droppable
758             dataSpace,
759             Rect(blocks.front().crop().left,
760                  blocks.front().crop().top,
761                  blocks.front().crop().right(),
762                  blocks.front().crop().bottom()),
763             videoScalingMode,
764             transform,
765             Fence::NO_FENCE, 0);
766     if (hdrStaticInfo || hdr10PlusInfo) {
767         HdrMetadata hdr;
768         if (hdrStaticInfo) {
769             // If mastering max and min luminance fields are 0, do not use them.
770             // It indicates the value may not be present in the stream.
771             if (hdrStaticInfo->mastering.maxLuminance > 0.0f &&
772                 hdrStaticInfo->mastering.minLuminance > 0.0f) {
773                 struct android_smpte2086_metadata smpte2086_meta = {
774                     .displayPrimaryRed = {
775                         hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
776                     },
777                     .displayPrimaryGreen = {
778                         hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
779                     },
780                     .displayPrimaryBlue = {
781                         hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
782                     },
783                     .whitePoint = {
784                         hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
785                     },
786                     .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
787                     .minLuminance = hdrStaticInfo->mastering.minLuminance,
788                 };
789                 hdr.validTypes |= HdrMetadata::SMPTE2086;
790                 hdr.smpte2086 = smpte2086_meta;
791             }
792             // If the content light level fields are 0, do not use them, it
793             // indicates the value may not be present in the stream.
794             if (hdrStaticInfo->maxCll > 0.0f && hdrStaticInfo->maxFall > 0.0f) {
795                 struct android_cta861_3_metadata cta861_meta = {
796                     .maxContentLightLevel = hdrStaticInfo->maxCll,
797                     .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
798                 };
799                 hdr.validTypes |= HdrMetadata::CTA861_3;
800                 hdr.cta8613 = cta861_meta;
801             }
802         }
803         if (hdr10PlusInfo) {
804             hdr.validTypes |= HdrMetadata::HDR10PLUS;
805             hdr.hdr10plus.assign(
806                     hdr10PlusInfo->m.value,
807                     hdr10PlusInfo->m.value + hdr10PlusInfo->flexCount());
808         }
809         qbi.setHdrMetadata(hdr);
810     }
811     // we don't have dirty regions
812     qbi.setSurfaceDamage(Region::INVALID_REGION);
813     android::IGraphicBufferProducer::QueueBufferOutput qbo;
814     status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
815     if (result != OK) {
816         ALOGI("[%s] queueBuffer failed: %d", mName, result);
817         return result;
818     }
819     ALOGV("[%s] queue buffer successful", mName);
820 
821     int64_t mediaTimeUs = 0;
822     (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs);
823     mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs);
824 
825     return OK;
826 }
827 
discardBuffer(const sp<MediaCodecBuffer> & buffer)828 status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
829     ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
830     bool released = false;
831     {
832         Mutexed<Input>::Locked input(mInput);
833         if (input->buffers && input->buffers->releaseBuffer(buffer, nullptr, true)) {
834             released = true;
835         }
836     }
837     {
838         Mutexed<Output>::Locked output(mOutput);
839         if (output->buffers && output->buffers->releaseBuffer(buffer, nullptr)) {
840             released = true;
841         }
842     }
843     if (released) {
844         sendOutputBuffers();
845         feedInputBufferIfAvailable();
846     } else {
847         ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
848     }
849     return OK;
850 }
851 
getInputBufferArray(Vector<sp<MediaCodecBuffer>> * array)852 void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
853     array->clear();
854     Mutexed<Input>::Locked input(mInput);
855 
856     if (!input->buffers->isArrayMode()) {
857         input->buffers = input->buffers->toArrayMode(input->numSlots);
858     }
859 
860     input->buffers->getArray(array);
861 }
862 
getOutputBufferArray(Vector<sp<MediaCodecBuffer>> * array)863 void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
864     array->clear();
865     Mutexed<Output>::Locked output(mOutput);
866 
867     if (!output->buffers->isArrayMode()) {
868         output->buffers = output->buffers->toArrayMode(output->numSlots);
869     }
870 
871     output->buffers->getArray(array);
872 }
873 
start(const sp<AMessage> & inputFormat,const sp<AMessage> & outputFormat,bool buffersBoundToCodec)874 status_t CCodecBufferChannel::start(
875         const sp<AMessage> &inputFormat,
876         const sp<AMessage> &outputFormat,
877         bool buffersBoundToCodec) {
878     C2StreamBufferTypeSetting::input iStreamFormat(0u);
879     C2StreamBufferTypeSetting::output oStreamFormat(0u);
880     C2PortReorderBufferDepthTuning::output reorderDepth;
881     C2PortReorderKeySetting::output reorderKey;
882     C2PortActualDelayTuning::input inputDelay(0);
883     C2PortActualDelayTuning::output outputDelay(0);
884     C2ActualPipelineDelayTuning pipelineDelay(0);
885 
886     c2_status_t err = mComponent->query(
887             {
888                 &iStreamFormat,
889                 &oStreamFormat,
890                 &reorderDepth,
891                 &reorderKey,
892                 &inputDelay,
893                 &pipelineDelay,
894                 &outputDelay,
895             },
896             {},
897             C2_DONT_BLOCK,
898             nullptr);
899     if (err == C2_BAD_INDEX) {
900         if (!iStreamFormat || !oStreamFormat) {
901             return UNKNOWN_ERROR;
902         }
903     } else if (err != C2_OK) {
904         return UNKNOWN_ERROR;
905     }
906 
907     uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
908     uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
909     uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
910 
911     size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
912     size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
913 
914     // TODO: get this from input format
915     bool secure = mComponent->getName().find(".secure") != std::string::npos;
916 
917     std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
918     int poolMask = GetCodec2PoolMask();
919     C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
920 
921     if (inputFormat != nullptr) {
922         bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
923         C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
924                 API_REFLECTION |
925                 API_VALUES |
926                 API_CURRENT_VALUES |
927                 API_DEPENDENCY |
928                 API_SAME_INPUT_BUFFER);
929         std::shared_ptr<C2BlockPool> pool;
930         {
931             Mutexed<BlockPools>::Locked pools(mBlockPools);
932 
933             // set default allocator ID.
934             pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
935                                                 : preferredLinearId;
936 
937             // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
938             // from component, create the input block pool with given ID. Otherwise, use default IDs.
939             std::vector<std::unique_ptr<C2Param>> params;
940             C2ApiFeaturesSetting featuresSetting{apiFeatures};
941             err = mComponent->query({ &featuresSetting },
942                                     { C2PortAllocatorsTuning::input::PARAM_TYPE },
943                                     C2_DONT_BLOCK,
944                                     &params);
945             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
946                 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
947                         mName, params.size(), asString(err), err);
948             } else if (params.size() == 1) {
949                 C2PortAllocatorsTuning::input *inputAllocators =
950                     C2PortAllocatorsTuning::input::From(params[0].get());
951                 if (inputAllocators && inputAllocators->flexCount() > 0) {
952                     std::shared_ptr<C2Allocator> allocator;
953                     // verify allocator IDs and resolve default allocator
954                     allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator);
955                     if (allocator) {
956                         pools->inputAllocatorId = allocator->getId();
957                     } else {
958                         ALOGD("[%s] component requested invalid input allocator ID %u",
959                                 mName, inputAllocators->m.values[0]);
960                     }
961                 }
962             }
963             if (featuresSetting) {
964                 apiFeatures = featuresSetting.value;
965             }
966 
967             // TODO: use C2Component wrapper to associate this pool with ourselves
968             if ((poolMask >> pools->inputAllocatorId) & 1) {
969                 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool);
970                 ALOGD("[%s] Created input block pool with allocatorID %u => poolID %llu - %s (%d)",
971                         mName, pools->inputAllocatorId,
972                         (unsigned long long)(pool ? pool->getLocalId() : 111000111),
973                         asString(err), err);
974             } else {
975                 err = C2_NOT_FOUND;
976             }
977             if (err != C2_OK) {
978                 C2BlockPool::local_id_t inputPoolId =
979                     graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
980                 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool);
981                 ALOGD("[%s] Using basic input block pool with poolID %llu => got %llu - %s (%d)",
982                         mName, (unsigned long long)inputPoolId,
983                         (unsigned long long)(pool ? pool->getLocalId() : 111000111),
984                         asString(err), err);
985                 if (err != C2_OK) {
986                     return NO_MEMORY;
987                 }
988             }
989             pools->inputPool = pool;
990         }
991 
992         bool forceArrayMode = false;
993         Mutexed<Input>::Locked input(mInput);
994         input->inputDelay = inputDelayValue;
995         input->pipelineDelay = pipelineDelayValue;
996         input->numSlots = numInputSlots;
997         input->extraBuffers.flush();
998         input->numExtraSlots = 0u;
999         bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
1000         // For encrypted content, framework decrypts source buffer (ashmem) into
1001         // C2Buffers. Thus non-conforming codecs can process these.
1002         if (!buffersBoundToCodec && (hasCryptoOrDescrambler() || conforming)) {
1003             input->buffers.reset(new SlotInputBuffers(mName));
1004         } else if (graphic) {
1005             if (mInputSurface) {
1006                 input->buffers.reset(new DummyInputBuffers(mName));
1007             } else if (mMetaMode == MODE_ANW) {
1008                 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
1009                 // This is to ensure buffers do not get released prematurely.
1010                 // TODO: handle this without going into array mode
1011                 forceArrayMode = true;
1012             } else {
1013                 input->buffers.reset(new GraphicInputBuffers(mName));
1014             }
1015         } else {
1016             if (hasCryptoOrDescrambler()) {
1017                 int32_t capacity = kLinearBufferSize;
1018                 (void)inputFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1019                 if ((size_t)capacity > kMaxLinearBufferSize) {
1020                     ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1021                     capacity = kMaxLinearBufferSize;
1022                 }
1023                 if (mDealer == nullptr) {
1024                     mDealer = new MemoryDealer(
1025                             align(capacity, MemoryDealer::getAllocationAlignment())
1026                                 * (numInputSlots + 1),
1027                             "EncryptedLinearInputBuffers");
1028                     mDecryptDestination = mDealer->allocate((size_t)capacity);
1029                 }
1030                 if (mCrypto != nullptr && mHeapSeqNum < 0) {
1031                     sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
1032                     mHeapSeqNum = mCrypto->setHeap(heap);
1033                 } else {
1034                     mHeapSeqNum = -1;
1035                 }
1036                 input->buffers.reset(new EncryptedLinearInputBuffers(
1037                         secure, mDealer, mCrypto, mHeapSeqNum, (size_t)capacity,
1038                         numInputSlots, mName));
1039                 forceArrayMode = true;
1040             } else {
1041                 input->buffers.reset(new LinearInputBuffers(mName));
1042             }
1043         }
1044         input->buffers->setFormat(inputFormat);
1045 
1046         if (err == C2_OK) {
1047             input->buffers->setPool(pool);
1048         } else {
1049             // TODO: error
1050         }
1051 
1052         if (forceArrayMode) {
1053             input->buffers = input->buffers->toArrayMode(numInputSlots);
1054         }
1055     }
1056 
1057     if (outputFormat != nullptr) {
1058         sp<IGraphicBufferProducer> outputSurface;
1059         uint32_t outputGeneration;
1060         {
1061             Mutexed<OutputSurface>::Locked output(mOutputSurface);
1062             output->maxDequeueBuffers = numOutputSlots +
1063                     reorderDepth.value + kRenderingDepth;
1064             if (!secure) {
1065                 output->maxDequeueBuffers += numInputSlots;
1066             }
1067             outputSurface = output->surface ?
1068                     output->surface->getIGraphicBufferProducer() : nullptr;
1069             if (outputSurface) {
1070                 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1071             }
1072             outputGeneration = output->generation;
1073         }
1074 
1075         bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
1076         C2BlockPool::local_id_t outputPoolId_;
1077 
1078         {
1079             Mutexed<BlockPools>::Locked pools(mBlockPools);
1080 
1081             // set default allocator ID.
1082             pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
1083                                                  : preferredLinearId;
1084 
1085             // query C2PortAllocatorsTuning::output from component, or use default allocator if
1086             // unsuccessful.
1087             std::vector<std::unique_ptr<C2Param>> params;
1088             err = mComponent->query({ },
1089                                     { C2PortAllocatorsTuning::output::PARAM_TYPE },
1090                                     C2_DONT_BLOCK,
1091                                     &params);
1092             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1093                 ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
1094                         mName, params.size(), asString(err), err);
1095             } else if (err == C2_OK && params.size() == 1) {
1096                 C2PortAllocatorsTuning::output *outputAllocators =
1097                     C2PortAllocatorsTuning::output::From(params[0].get());
1098                 if (outputAllocators && outputAllocators->flexCount() > 0) {
1099                     std::shared_ptr<C2Allocator> allocator;
1100                     // verify allocator IDs and resolve default allocator
1101                     allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator);
1102                     if (allocator) {
1103                         pools->outputAllocatorId = allocator->getId();
1104                     } else {
1105                         ALOGD("[%s] component requested invalid output allocator ID %u",
1106                                 mName, outputAllocators->m.values[0]);
1107                     }
1108                 }
1109             }
1110 
1111             // use bufferqueue if outputting to a surface.
1112             // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
1113             // if unsuccessful.
1114             if (outputSurface) {
1115                 params.clear();
1116                 err = mComponent->query({ },
1117                                         { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
1118                                         C2_DONT_BLOCK,
1119                                         &params);
1120                 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1121                     ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
1122                             mName, params.size(), asString(err), err);
1123                 } else if (err == C2_OK && params.size() == 1) {
1124                     C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
1125                         C2PortSurfaceAllocatorTuning::output::From(params[0].get());
1126                     if (surfaceAllocator) {
1127                         std::shared_ptr<C2Allocator> allocator;
1128                         // verify allocator IDs and resolve default allocator
1129                         allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
1130                         if (allocator) {
1131                             pools->outputAllocatorId = allocator->getId();
1132                         } else {
1133                             ALOGD("[%s] component requested invalid surface output allocator ID %u",
1134                                     mName, surfaceAllocator->value);
1135                             err = C2_BAD_VALUE;
1136                         }
1137                     }
1138                 }
1139                 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
1140                         && err != C2_OK
1141                         && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
1142                     pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
1143                 }
1144             }
1145 
1146             if ((poolMask >> pools->outputAllocatorId) & 1) {
1147                 err = mComponent->createBlockPool(
1148                         pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
1149                 ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
1150                         mName, pools->outputAllocatorId,
1151                         (unsigned long long)pools->outputPoolId,
1152                         asString(err));
1153             } else {
1154                 err = C2_NOT_FOUND;
1155             }
1156             if (err != C2_OK) {
1157                 // use basic pool instead
1158                 pools->outputPoolId =
1159                     graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1160             }
1161 
1162             // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to
1163             // component.
1164             std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning =
1165                     C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
1166 
1167             std::vector<std::unique_ptr<C2SettingResult>> failures;
1168             err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
1169             ALOGD("[%s] Configured output block pool ids %llu => %s",
1170                     mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
1171             outputPoolId_ = pools->outputPoolId;
1172         }
1173 
1174         Mutexed<Output>::Locked output(mOutput);
1175         output->outputDelay = outputDelayValue;
1176         output->numSlots = numOutputSlots;
1177         if (graphic) {
1178             if (outputSurface || !buffersBoundToCodec) {
1179                 output->buffers.reset(new GraphicOutputBuffers(mName));
1180             } else {
1181                 output->buffers.reset(new RawGraphicOutputBuffers(mName));
1182             }
1183         } else {
1184             output->buffers.reset(new LinearOutputBuffers(mName));
1185         }
1186         output->buffers->setFormat(outputFormat);
1187 
1188         output->buffers->clearStash();
1189         if (reorderDepth) {
1190             output->buffers->setReorderDepth(reorderDepth.value);
1191         }
1192         if (reorderKey) {
1193             output->buffers->setReorderKey(reorderKey.value);
1194         }
1195 
1196         // Try to set output surface to created block pool if given.
1197         if (outputSurface) {
1198             mComponent->setOutputSurface(
1199                     outputPoolId_,
1200                     outputSurface,
1201                     outputGeneration);
1202         }
1203 
1204         if (oStreamFormat.value == C2BufferData::LINEAR) {
1205             if (buffersBoundToCodec) {
1206                 // WORKAROUND: if we're using early CSD workaround we convert to
1207                 //             array mode, to appease apps assuming the output
1208                 //             buffers to be of the same size.
1209                 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1210             }
1211 
1212             int32_t channelCount;
1213             int32_t sampleRate;
1214             if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
1215                     && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
1216                 int32_t delay = 0;
1217                 int32_t padding = 0;;
1218                 if (!outputFormat->findInt32("encoder-delay", &delay)) {
1219                     delay = 0;
1220                 }
1221                 if (!outputFormat->findInt32("encoder-padding", &padding)) {
1222                     padding = 0;
1223                 }
1224                 if (delay || padding) {
1225                     // We need write access to the buffers, and we're already in
1226                     // array mode.
1227                     output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
1228                 }
1229             }
1230         }
1231     }
1232 
1233     // Set up pipeline control. This has to be done after mInputBuffers and
1234     // mOutputBuffers are initialized to make sure that lingering callbacks
1235     // about buffers from the previous generation do not interfere with the
1236     // newly initialized pipeline capacity.
1237 
1238     {
1239         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
1240         watcher->inputDelay(inputDelayValue)
1241                 .pipelineDelay(pipelineDelayValue)
1242                 .outputDelay(outputDelayValue)
1243                 .smoothnessFactor(kSmoothnessFactor);
1244         watcher->flush();
1245     }
1246 
1247     mInputMetEos = false;
1248     mSync.start();
1249     return OK;
1250 }
1251 
requestInitialInputBuffers()1252 status_t CCodecBufferChannel::requestInitialInputBuffers() {
1253     if (mInputSurface) {
1254         return OK;
1255     }
1256 
1257     C2StreamBufferTypeSetting::output oStreamFormat(0u);
1258     C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
1259     c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
1260     if (err != C2_OK && err != C2_BAD_INDEX) {
1261         return UNKNOWN_ERROR;
1262     }
1263     size_t numInputSlots = mInput.lock()->numSlots;
1264 
1265     struct ClientInputBuffer {
1266         size_t index;
1267         sp<MediaCodecBuffer> buffer;
1268         size_t capacity;
1269     };
1270     std::list<ClientInputBuffer> clientInputBuffers;
1271 
1272     {
1273         Mutexed<Input>::Locked input(mInput);
1274         while (clientInputBuffers.size() < numInputSlots) {
1275             ClientInputBuffer clientInputBuffer;
1276             if (!input->buffers->requestNewBuffer(&clientInputBuffer.index,
1277                                                   &clientInputBuffer.buffer)) {
1278                 break;
1279             }
1280             clientInputBuffer.capacity = clientInputBuffer.buffer->capacity();
1281             clientInputBuffers.emplace_back(std::move(clientInputBuffer));
1282         }
1283     }
1284     if (clientInputBuffers.empty()) {
1285         ALOGW("[%s] start: cannot allocate memory at all", mName);
1286         return NO_MEMORY;
1287     } else if (clientInputBuffers.size() < numInputSlots) {
1288         ALOGD("[%s] start: cannot allocate memory for all slots, "
1289               "only %zu buffers allocated",
1290               mName, clientInputBuffers.size());
1291     } else {
1292         ALOGV("[%s] %zu initial input buffers available",
1293               mName, clientInputBuffers.size());
1294     }
1295     // Sort input buffers by their capacities in increasing order.
1296     clientInputBuffers.sort(
1297             [](const ClientInputBuffer& a, const ClientInputBuffer& b) {
1298                 return a.capacity < b.capacity;
1299             });
1300 
1301     {
1302         Mutexed<std::list<sp<ABuffer>>>::Locked configs(mFlushedConfigs);
1303         if (!configs->empty()) {
1304             while (!configs->empty()) {
1305                 sp<ABuffer> config = configs->front();
1306                 configs->pop_front();
1307                 // Find the smallest input buffer that can fit the config.
1308                 auto i = std::find_if(
1309                         clientInputBuffers.begin(),
1310                         clientInputBuffers.end(),
1311                         [cfgSize = config->size()](const ClientInputBuffer& b) {
1312                             return b.capacity >= cfgSize;
1313                         });
1314                 if (i == clientInputBuffers.end()) {
1315                     ALOGW("[%s] no input buffer large enough for the config "
1316                           "(%zu bytes)",
1317                           mName, config->size());
1318                     return NO_MEMORY;
1319                 }
1320                 sp<MediaCodecBuffer> buffer = i->buffer;
1321                 memcpy(buffer->base(), config->data(), config->size());
1322                 buffer->setRange(0, config->size());
1323                 buffer->meta()->clear();
1324                 buffer->meta()->setInt64("timeUs", 0);
1325                 buffer->meta()->setInt32("csd", 1);
1326                 if (queueInputBufferInternal(buffer) != OK) {
1327                     ALOGW("[%s] Error while queueing a flushed config",
1328                           mName);
1329                     return UNKNOWN_ERROR;
1330                 }
1331                 clientInputBuffers.erase(i);
1332             }
1333         } else if (oStreamFormat.value == C2BufferData::LINEAR &&
1334                    (!prepend || prepend.value == PREPEND_HEADER_TO_NONE)) {
1335             sp<MediaCodecBuffer> buffer = clientInputBuffers.front().buffer;
1336             // WORKAROUND: Some apps expect CSD available without queueing
1337             //             any input. Queue an empty buffer to get the CSD.
1338             buffer->setRange(0, 0);
1339             buffer->meta()->clear();
1340             buffer->meta()->setInt64("timeUs", 0);
1341             if (queueInputBufferInternal(buffer) != OK) {
1342                 ALOGW("[%s] Error while queueing an empty buffer to get CSD",
1343                       mName);
1344                 return UNKNOWN_ERROR;
1345             }
1346             clientInputBuffers.pop_front();
1347         }
1348     }
1349 
1350     for (const ClientInputBuffer& clientInputBuffer: clientInputBuffers) {
1351         mCallback->onInputBufferAvailable(
1352                 clientInputBuffer.index,
1353                 clientInputBuffer.buffer);
1354     }
1355 
1356     return OK;
1357 }
1358 
stop()1359 void CCodecBufferChannel::stop() {
1360     mSync.stop();
1361     mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
1362     if (mInputSurface != nullptr) {
1363         mInputSurface.reset();
1364     }
1365     mPipelineWatcher.lock()->flush();
1366 }
1367 
reset()1368 void CCodecBufferChannel::reset() {
1369     stop();
1370     {
1371         Mutexed<Input>::Locked input(mInput);
1372         input->buffers.reset(new DummyInputBuffers(""));
1373         input->extraBuffers.flush();
1374     }
1375     {
1376         Mutexed<Output>::Locked output(mOutput);
1377         output->buffers.reset();
1378     }
1379 }
1380 
release()1381 void CCodecBufferChannel::release() {
1382     mComponent.reset();
1383     mInputAllocator.reset();
1384     mOutputSurface.lock()->surface.clear();
1385     {
1386         Mutexed<BlockPools>::Locked blockPools{mBlockPools};
1387         blockPools->inputPool.reset();
1388         blockPools->outputPoolIntf.reset();
1389     }
1390     setCrypto(nullptr);
1391     setDescrambler(nullptr);
1392 }
1393 
1394 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1395 void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1396     ALOGV("[%s] flush", mName);
1397     {
1398         Mutexed<std::list<sp<ABuffer>>>::Locked configs(mFlushedConfigs);
1399         for (const std::unique_ptr<C2Work> &work : flushedWork) {
1400             if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
1401                 continue;
1402             }
1403             if (work->input.buffers.empty()
1404                     || work->input.buffers.front()->data().linearBlocks().empty()) {
1405                 ALOGD("[%s] no linear codec config data found", mName);
1406                 continue;
1407             }
1408             C2ReadView view =
1409                     work->input.buffers.front()->data().linearBlocks().front().map().get();
1410             if (view.error() != C2_OK) {
1411                 ALOGD("[%s] failed to map flushed codec config data: %d", mName, view.error());
1412                 continue;
1413             }
1414             configs->push_back(ABuffer::CreateAsCopy(view.data(), view.capacity()));
1415             ALOGV("[%s] stashed flushed codec config data (size=%u)", mName, view.capacity());
1416         }
1417     }
1418     {
1419         Mutexed<Input>::Locked input(mInput);
1420         input->buffers->flush();
1421         input->extraBuffers.flush();
1422     }
1423     {
1424         Mutexed<Output>::Locked output(mOutput);
1425         if (output->buffers) {
1426             output->buffers->flush(flushedWork);
1427             output->buffers->flushStash();
1428         }
1429     }
1430     mPipelineWatcher.lock()->flush();
1431 }
1432 
onWorkDone(std::unique_ptr<C2Work> work,const sp<AMessage> & outputFormat,const C2StreamInitDataInfo::output * initData)1433 void CCodecBufferChannel::onWorkDone(
1434         std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
1435         const C2StreamInitDataInfo::output *initData) {
1436     if (handleWork(std::move(work), outputFormat, initData)) {
1437         feedInputBufferIfAvailable();
1438     }
1439 }
1440 
onInputBufferDone(uint64_t frameIndex,size_t arrayIndex)1441 void CCodecBufferChannel::onInputBufferDone(
1442         uint64_t frameIndex, size_t arrayIndex) {
1443     if (mInputSurface) {
1444         return;
1445     }
1446     std::shared_ptr<C2Buffer> buffer =
1447             mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
1448     bool newInputSlotAvailable;
1449     {
1450         Mutexed<Input>::Locked input(mInput);
1451         newInputSlotAvailable = input->buffers->expireComponentBuffer(buffer);
1452         if (!newInputSlotAvailable) {
1453             (void)input->extraBuffers.expireComponentBuffer(buffer);
1454         }
1455     }
1456     if (newInputSlotAvailable) {
1457         feedInputBufferIfAvailable();
1458     }
1459 }
1460 
handleWork(std::unique_ptr<C2Work> work,const sp<AMessage> & outputFormat,const C2StreamInitDataInfo::output * initData)1461 bool CCodecBufferChannel::handleWork(
1462         std::unique_ptr<C2Work> work,
1463         const sp<AMessage> &outputFormat,
1464         const C2StreamInitDataInfo::output *initData) {
1465     {
1466         Mutexed<Output>::Locked output(mOutput);
1467         if (!output->buffers) {
1468             return false;
1469         }
1470     }
1471 
1472     // Whether the output buffer should be reported to the client or not.
1473     bool notifyClient = false;
1474 
1475     if (work->result == C2_OK){
1476         notifyClient = true;
1477     } else if (work->result == C2_NOT_FOUND) {
1478         ALOGD("[%s] flushed work; ignored.", mName);
1479     } else {
1480         // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
1481         // the config update.
1482         ALOGD("[%s] work failed to complete: %d", mName, work->result);
1483         mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
1484         return false;
1485     }
1486 
1487     if ((work->input.ordinal.frameIndex -
1488             mFirstValidFrameIndex.load()).peek() < 0) {
1489         // Discard frames from previous generation.
1490         ALOGD("[%s] Discard frames from previous generation.", mName);
1491         notifyClient = false;
1492     }
1493 
1494     if (mInputSurface == nullptr && (work->worklets.size() != 1u
1495             || !work->worklets.front()
1496             || !(work->worklets.front()->output.flags &
1497                  C2FrameData::FLAG_INCOMPLETE))) {
1498         mPipelineWatcher.lock()->onWorkDone(
1499                 work->input.ordinal.frameIndex.peeku());
1500     }
1501 
1502     // NOTE: MediaCodec usage supposedly have only one worklet
1503     if (work->worklets.size() != 1u) {
1504         ALOGI("[%s] onWorkDone: incorrect number of worklets: %zu",
1505                 mName, work->worklets.size());
1506         mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1507         return false;
1508     }
1509 
1510     const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
1511 
1512     std::shared_ptr<C2Buffer> buffer;
1513     // NOTE: MediaCodec usage supposedly have only one output stream.
1514     if (worklet->output.buffers.size() > 1u) {
1515         ALOGI("[%s] onWorkDone: incorrect number of output buffers: %zu",
1516                 mName, worklet->output.buffers.size());
1517         mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1518         return false;
1519     } else if (worklet->output.buffers.size() == 1u) {
1520         buffer = worklet->output.buffers[0];
1521         if (!buffer) {
1522             ALOGD("[%s] onWorkDone: nullptr found in buffers; ignored.", mName);
1523         }
1524     }
1525 
1526     std::optional<uint32_t> newInputDelay, newPipelineDelay;
1527     while (!worklet->output.configUpdate.empty()) {
1528         std::unique_ptr<C2Param> param;
1529         worklet->output.configUpdate.back().swap(param);
1530         worklet->output.configUpdate.pop_back();
1531         switch (param->coreIndex().coreIndex()) {
1532             case C2PortReorderBufferDepthTuning::CORE_INDEX: {
1533                 C2PortReorderBufferDepthTuning::output reorderDepth;
1534                 if (reorderDepth.updateFrom(*param)) {
1535                     bool secure = mComponent->getName().find(".secure") !=
1536                                   std::string::npos;
1537                     mOutput.lock()->buffers->setReorderDepth(
1538                             reorderDepth.value);
1539                     ALOGV("[%s] onWorkDone: updated reorder depth to %u",
1540                           mName, reorderDepth.value);
1541                     size_t numOutputSlots = mOutput.lock()->numSlots;
1542                     size_t numInputSlots = mInput.lock()->numSlots;
1543                     Mutexed<OutputSurface>::Locked output(mOutputSurface);
1544                     output->maxDequeueBuffers = numOutputSlots +
1545                             reorderDepth.value + kRenderingDepth;
1546                     if (!secure) {
1547                         output->maxDequeueBuffers += numInputSlots;
1548                     }
1549                     if (output->surface) {
1550                         output->surface->setMaxDequeuedBufferCount(
1551                                 output->maxDequeueBuffers);
1552                     }
1553                 } else {
1554                     ALOGD("[%s] onWorkDone: failed to read reorder depth",
1555                           mName);
1556                 }
1557                 break;
1558             }
1559             case C2PortReorderKeySetting::CORE_INDEX: {
1560                 C2PortReorderKeySetting::output reorderKey;
1561                 if (reorderKey.updateFrom(*param)) {
1562                     mOutput.lock()->buffers->setReorderKey(reorderKey.value);
1563                     ALOGV("[%s] onWorkDone: updated reorder key to %u",
1564                           mName, reorderKey.value);
1565                 } else {
1566                     ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
1567                 }
1568                 break;
1569             }
1570             case C2PortActualDelayTuning::CORE_INDEX: {
1571                 if (param->isGlobal()) {
1572                     C2ActualPipelineDelayTuning pipelineDelay;
1573                     if (pipelineDelay.updateFrom(*param)) {
1574                         ALOGV("[%s] onWorkDone: updating pipeline delay %u",
1575                               mName, pipelineDelay.value);
1576                         newPipelineDelay = pipelineDelay.value;
1577                         (void)mPipelineWatcher.lock()->pipelineDelay(
1578                                 pipelineDelay.value);
1579                     }
1580                 }
1581                 if (param->forInput()) {
1582                     C2PortActualDelayTuning::input inputDelay;
1583                     if (inputDelay.updateFrom(*param)) {
1584                         ALOGV("[%s] onWorkDone: updating input delay %u",
1585                               mName, inputDelay.value);
1586                         newInputDelay = inputDelay.value;
1587                         (void)mPipelineWatcher.lock()->inputDelay(
1588                                 inputDelay.value);
1589                     }
1590                 }
1591                 if (param->forOutput()) {
1592                     C2PortActualDelayTuning::output outputDelay;
1593                     if (outputDelay.updateFrom(*param)) {
1594                         ALOGV("[%s] onWorkDone: updating output delay %u",
1595                               mName, outputDelay.value);
1596                         bool secure = mComponent->getName().find(".secure") !=
1597                                       std::string::npos;
1598                         (void)mPipelineWatcher.lock()->outputDelay(
1599                                 outputDelay.value);
1600 
1601                         bool outputBuffersChanged = false;
1602                         size_t numOutputSlots = 0;
1603                         size_t numInputSlots = mInput.lock()->numSlots;
1604                         {
1605                             Mutexed<Output>::Locked output(mOutput);
1606                             if (!output->buffers) {
1607                                 return false;
1608                             }
1609                             output->outputDelay = outputDelay.value;
1610                             numOutputSlots = outputDelay.value +
1611                                              kSmoothnessFactor;
1612                             if (output->numSlots < numOutputSlots) {
1613                                 output->numSlots = numOutputSlots;
1614                                 if (output->buffers->isArrayMode()) {
1615                                     OutputBuffersArray *array =
1616                                         (OutputBuffersArray *)output->buffers.get();
1617                                     ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
1618                                           mName, numOutputSlots);
1619                                     array->grow(numOutputSlots);
1620                                     outputBuffersChanged = true;
1621                                 }
1622                             }
1623                             numOutputSlots = output->numSlots;
1624                         }
1625 
1626                         if (outputBuffersChanged) {
1627                             mCCodecCallback->onOutputBuffersChanged();
1628                         }
1629 
1630                         uint32_t depth = mOutput.lock()->buffers->getReorderDepth();
1631                         Mutexed<OutputSurface>::Locked output(mOutputSurface);
1632                         output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
1633                         if (!secure) {
1634                             output->maxDequeueBuffers += numInputSlots;
1635                         }
1636                         if (output->surface) {
1637                             output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1638                         }
1639                     }
1640                 }
1641                 break;
1642             }
1643             default:
1644                 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
1645                       mName, param->index());
1646                 break;
1647         }
1648     }
1649     if (newInputDelay || newPipelineDelay) {
1650         Mutexed<Input>::Locked input(mInput);
1651         size_t newNumSlots =
1652             newInputDelay.value_or(input->inputDelay) +
1653             newPipelineDelay.value_or(input->pipelineDelay) +
1654             kSmoothnessFactor;
1655         if (input->buffers->isArrayMode()) {
1656             if (input->numSlots >= newNumSlots) {
1657                 input->numExtraSlots = 0;
1658             } else {
1659                 input->numExtraSlots = newNumSlots - input->numSlots;
1660             }
1661             ALOGV("[%s] onWorkDone: updated number of extra slots to %zu (input array mode)",
1662                   mName, input->numExtraSlots);
1663         } else {
1664             input->numSlots = newNumSlots;
1665         }
1666     }
1667 
1668     int32_t flags = 0;
1669     if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
1670         flags |= MediaCodec::BUFFER_FLAG_EOS;
1671         ALOGV("[%s] onWorkDone: output EOS", mName);
1672     }
1673 
1674     // WORKAROUND: adjust output timestamp based on client input timestamp and codec
1675     // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
1676     // the codec input timestamp, but client output timestamp should (reported in timeUs)
1677     // shall correspond to the client input timesamp (in customOrdinal). By using the
1678     // delta between the two, this allows for some timestamp deviation - e.g. if one input
1679     // produces multiple output.
1680     c2_cntr64_t timestamp =
1681         worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
1682                 - work->input.ordinal.timestamp;
1683     if (mInputSurface != nullptr) {
1684         // When using input surface we need to restore the original input timestamp.
1685         timestamp = work->input.ordinal.customOrdinal;
1686     }
1687     ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
1688           mName,
1689           work->input.ordinal.customOrdinal.peekll(),
1690           work->input.ordinal.timestamp.peekll(),
1691           worklet->output.ordinal.timestamp.peekll(),
1692           timestamp.peekll());
1693 
1694     // csd cannot be re-ordered and will always arrive first.
1695     if (initData != nullptr) {
1696         Mutexed<Output>::Locked output(mOutput);
1697         if (output->buffers && outputFormat) {
1698             output->buffers->updateSkipCutBuffer(outputFormat);
1699             output->buffers->setFormat(outputFormat);
1700         }
1701         if (!notifyClient) {
1702             return false;
1703         }
1704         size_t index;
1705         sp<MediaCodecBuffer> outBuffer;
1706         if (output->buffers && output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
1707             outBuffer->meta()->setInt64("timeUs", timestamp.peek());
1708             outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG);
1709             ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
1710 
1711             output.unlock();
1712             mCallback->onOutputBufferAvailable(index, outBuffer);
1713         } else {
1714             ALOGD("[%s] onWorkDone: unable to register csd", mName);
1715             output.unlock();
1716             mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1717             return false;
1718         }
1719     }
1720 
1721     if (notifyClient && !buffer && !flags) {
1722         ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
1723               mName, work->input.ordinal.frameIndex.peekull());
1724         notifyClient = false;
1725     }
1726 
1727     if (buffer) {
1728         for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
1729             // TODO: properly translate these to metadata
1730             switch (info->coreIndex().coreIndex()) {
1731                 case C2StreamPictureTypeMaskInfo::CORE_INDEX:
1732                     if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2Config::SYNC_FRAME) {
1733                         flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
1734                     }
1735                     break;
1736                 default:
1737                     break;
1738             }
1739         }
1740     }
1741 
1742     {
1743         Mutexed<Output>::Locked output(mOutput);
1744         if (!output->buffers) {
1745             return false;
1746         }
1747         output->buffers->pushToStash(
1748                 buffer,
1749                 notifyClient,
1750                 timestamp.peek(),
1751                 flags,
1752                 outputFormat,
1753                 worklet->output.ordinal);
1754     }
1755     sendOutputBuffers();
1756     return true;
1757 }
1758 
sendOutputBuffers()1759 void CCodecBufferChannel::sendOutputBuffers() {
1760     OutputBuffers::BufferAction action;
1761     size_t index;
1762     sp<MediaCodecBuffer> outBuffer;
1763     std::shared_ptr<C2Buffer> c2Buffer;
1764 
1765     while (true) {
1766         Mutexed<Output>::Locked output(mOutput);
1767         if (!output->buffers) {
1768             return;
1769         }
1770         action = output->buffers->popFromStashAndRegister(
1771                 &c2Buffer, &index, &outBuffer);
1772         switch (action) {
1773         case OutputBuffers::SKIP:
1774             return;
1775         case OutputBuffers::DISCARD:
1776             break;
1777         case OutputBuffers::NOTIFY_CLIENT:
1778             output.unlock();
1779             mCallback->onOutputBufferAvailable(index, outBuffer);
1780             break;
1781         case OutputBuffers::REALLOCATE:
1782             if (!output->buffers->isArrayMode()) {
1783                 output->buffers =
1784                     output->buffers->toArrayMode(output->numSlots);
1785             }
1786             static_cast<OutputBuffersArray*>(output->buffers.get())->
1787                     realloc(c2Buffer);
1788             output.unlock();
1789             mCCodecCallback->onOutputBuffersChanged();
1790             break;
1791         case OutputBuffers::RETRY:
1792             ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
1793                   mName);
1794             return;
1795         default:
1796             LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
1797                     "corrupted BufferAction value (%d) "
1798                     "returned from popFromStashAndRegister.",
1799                     mName, int(action));
1800             return;
1801         }
1802     }
1803 }
1804 
setSurface(const sp<Surface> & newSurface)1805 status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) {
1806     static std::atomic_uint32_t surfaceGeneration{0};
1807     uint32_t generation = (getpid() << 10) |
1808             ((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1)
1809                 & ((1 << 10) - 1));
1810 
1811     sp<IGraphicBufferProducer> producer;
1812     if (newSurface) {
1813         newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
1814         newSurface->setDequeueTimeout(kDequeueTimeoutNs);
1815         newSurface->setMaxDequeuedBufferCount(mOutputSurface.lock()->maxDequeueBuffers);
1816         producer = newSurface->getIGraphicBufferProducer();
1817         producer->setGenerationNumber(generation);
1818     } else {
1819         ALOGE("[%s] setting output surface to null", mName);
1820         return INVALID_OPERATION;
1821     }
1822 
1823     std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
1824     C2BlockPool::local_id_t outputPoolId;
1825     {
1826         Mutexed<BlockPools>::Locked pools(mBlockPools);
1827         outputPoolId = pools->outputPoolId;
1828         outputPoolIntf = pools->outputPoolIntf;
1829     }
1830 
1831     if (outputPoolIntf) {
1832         if (mComponent->setOutputSurface(
1833                 outputPoolId,
1834                 producer,
1835                 generation) != C2_OK) {
1836             ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
1837             return INVALID_OPERATION;
1838         }
1839     }
1840 
1841     {
1842         Mutexed<OutputSurface>::Locked output(mOutputSurface);
1843         output->surface = newSurface;
1844         output->generation = generation;
1845     }
1846 
1847     return OK;
1848 }
1849 
elapsed()1850 PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
1851     // When client pushed EOS, we want all the work to be done quickly.
1852     // Otherwise, component may have stalled work due to input starvation up to
1853     // the sum of the delay in the pipeline.
1854     size_t n = 0;
1855     if (!mInputMetEos) {
1856         size_t outputDelay = mOutput.lock()->outputDelay;
1857         Mutexed<Input>::Locked input(mInput);
1858         n = input->inputDelay + input->pipelineDelay + outputDelay;
1859     }
1860     return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
1861 }
1862 
setMetaMode(MetaMode mode)1863 void CCodecBufferChannel::setMetaMode(MetaMode mode) {
1864     mMetaMode = mode;
1865 }
1866 
setCrypto(const sp<ICrypto> & crypto)1867 void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
1868     if (mCrypto != nullptr) {
1869         for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
1870             mCrypto->unsetHeap(entry.second);
1871         }
1872         mHeapSeqNumMap.clear();
1873         if (mHeapSeqNum >= 0) {
1874             mCrypto->unsetHeap(mHeapSeqNum);
1875             mHeapSeqNum = -1;
1876         }
1877     }
1878     mCrypto = crypto;
1879 }
1880 
setDescrambler(const sp<IDescrambler> & descrambler)1881 void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
1882     mDescrambler = descrambler;
1883 }
1884 
toStatusT(c2_status_t c2s,c2_operation_t c2op)1885 status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
1886     // C2_OK is always translated to OK.
1887     if (c2s == C2_OK) {
1888         return OK;
1889     }
1890 
1891     // Operation-dependent translation
1892     // TODO: Add as necessary
1893     switch (c2op) {
1894     case C2_OPERATION_Component_start:
1895         switch (c2s) {
1896         case C2_NO_MEMORY:
1897             return NO_MEMORY;
1898         default:
1899             return UNKNOWN_ERROR;
1900         }
1901     default:
1902         break;
1903     }
1904 
1905     // Backup operation-agnostic translation
1906     switch (c2s) {
1907     case C2_BAD_INDEX:
1908         return BAD_INDEX;
1909     case C2_BAD_VALUE:
1910         return BAD_VALUE;
1911     case C2_BLOCKING:
1912         return WOULD_BLOCK;
1913     case C2_DUPLICATE:
1914         return ALREADY_EXISTS;
1915     case C2_NO_INIT:
1916         return NO_INIT;
1917     case C2_NO_MEMORY:
1918         return NO_MEMORY;
1919     case C2_NOT_FOUND:
1920         return NAME_NOT_FOUND;
1921     case C2_TIMED_OUT:
1922         return TIMED_OUT;
1923     case C2_BAD_STATE:
1924     case C2_CANCELED:
1925     case C2_CANNOT_DO:
1926     case C2_CORRUPTED:
1927     case C2_OMITTED:
1928     case C2_REFUSED:
1929         return UNKNOWN_ERROR;
1930     default:
1931         return -static_cast<status_t>(c2s);
1932     }
1933 }
1934 
1935 }  // namespace android
1936