diff options
| author | android-build-team Robot <android-build-team-robot@google.com> | 2018-11-19 23:21:31 +0000 |
|---|---|---|
| committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-11-19 23:21:31 +0000 |
| commit | ca5eabc93a21e4f79e08c6a4d2f7da5c2ef228b6 (patch) | |
| tree | 602cc73d22c17abcd4f9e2ee21a45ab7c750fc8d | |
| parent | a903c8827193896914957a290451bf45cc5a647f (diff) | |
| parent | bd29ddc477f05341b996badb9604eadb5e2413b4 (diff) | |
| download | platform_hardware_google_av-ca5eabc93a21e4f79e08c6a4d2f7da5c2ef228b6.tar.gz platform_hardware_google_av-ca5eabc93a21e4f79e08c6a4d2f7da5c2ef228b6.tar.bz2 platform_hardware_google_av-ca5eabc93a21e4f79e08c6a4d2f7da5c2ef228b6.zip | |
Merge cherrypicks of [5556008, 5556009, 5556010, 5556011, 5556012, 5556013, 5554791, 5554792, 5554793] into pi-qpr2-release
Change-Id: Id1e7884861c7e892d1b3043c107ad4ee24a36f4d
| -rw-r--r-- | media/codecs/aac/C2SoftAacEnc.cpp | 131 | ||||
| -rw-r--r-- | media/codecs/aac/C2SoftAacEnc.h | 3 | ||||
| -rw-r--r-- | media/codecs/base/SimpleC2Component.cpp | 30 | ||||
| -rw-r--r-- | media/codecs/base/include/SimpleC2Component.h | 18 | ||||
| -rw-r--r-- | media/sfplugin/CCodec.cpp | 13 | ||||
| -rw-r--r-- | media/sfplugin/CCodecBufferChannel.cpp | 444 | ||||
| -rw-r--r-- | media/sfplugin/CCodecBufferChannel.h | 71 |
7 files changed, 196 insertions, 514 deletions
diff --git a/media/codecs/aac/C2SoftAacEnc.cpp b/media/codecs/aac/C2SoftAacEnc.cpp index 285a6fb..054a08d 100644 --- a/media/codecs/aac/C2SoftAacEnc.cpp +++ b/media/codecs/aac/C2SoftAacEnc.cpp @@ -153,8 +153,7 @@ C2SoftAacEnc::C2SoftAacEnc( mSentCodecSpecificData(false), mInputSize(0), mInputTimeUs(-1ll), - mSignalledError(false), - mOutIndex(0u) { + mSignalledError(false) { } C2SoftAacEnc::~C2SoftAacEnc() { @@ -344,6 +343,7 @@ void C2SoftAacEnc::process( data = view.data(); capacity = view.capacity(); } + uint64_t timestamp = mInputTimeUs.peeku(); size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0)) / mNumBytesPerInputFrame; @@ -351,11 +351,22 @@ void C2SoftAacEnc::process( capacity, mInputSize, numFrames, mNumBytesPerInputFrame); std::shared_ptr<C2LinearBlock> block; - std::shared_ptr<C2Buffer> buffer; std::unique_ptr<C2WriteView> wView; uint8_t *outPtr = temp; size_t outAvailable = 0u; - uint64_t inputIndex = work->input.ordinal.frameIndex.peeku(); + + if (numFrames) { + C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; + // TODO: error handling, proper usage, etc. + c2_status_t err = pool->fetchLinearBlock(mOutBufferSize * numFrames, usage, &block); + if (err != C2_OK) { + ALOGE("err = %d", err); + } + + wView.reset(new C2WriteView(block->map().get())); + outPtr = wView->data(); + outAvailable = wView->size(); + } AACENC_InArgs inargs; AACENC_OutArgs outargs; @@ -387,58 +398,15 @@ void C2SoftAacEnc::process( outBufDesc.bufSizes = outBufferSize; outBufDesc.bufElSizes = outBufferElSize; + // Encode the mInputFrame, which is treated as a modulo buffer AACENC_ERROR encoderErr = AACENC_OK; - - class FillWork { - public: - FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal, - const std::shared_ptr<C2Buffer> &buffer) - : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) { - } - ~FillWork() = default; - - void operator()(const std::unique_ptr<C2Work> &work) { - work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags; - work->worklets.front()->output.buffers.clear(); - work->worklets.front()->output.ordinal = mOrdinal; - work->workletsProcessed = 1u; - work->result = C2_OK; - if (mBuffer) { - work->worklets.front()->output.buffers.push_back(mBuffer); - } - ALOGV("timestamp = %lld, index = %lld, w/%s buffer", - mOrdinal.timestamp.peekll(), - mOrdinal.frameIndex.peekll(), - mBuffer ? "" : "o"); - } - - private: - const uint32_t mFlags; - const C2WorkOrdinalStruct mOrdinal; - const std::shared_ptr<C2Buffer> mBuffer; - }; - - C2WorkOrdinalStruct outOrdinal = work->input.ordinal; + size_t nOutputBytes = 0; while (encoderErr == AACENC_OK && inargs.numInSamples > 0) { - if (numFrames && !block) { - C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; - // TODO: error handling, proper usage, etc. - c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block); - if (err != C2_OK) { - ALOGE("err = %d", err); - } - - wView.reset(new C2WriteView(block->map().get())); - outPtr = wView->data(); - outAvailable = wView->size(); - --numFrames; - } - memset(&outargs, 0, sizeof(outargs)); outBuffer[0] = outPtr; - outBufferSize[0] = outAvailable; + outBufferSize[0] = outAvailable - nOutputBytes; encoderErr = aacEncEncode(mAACEncoder, &inBufDesc, @@ -447,31 +415,17 @@ void C2SoftAacEnc::process( &outargs); if (encoderErr == AACENC_OK) { - if (buffer) { - outOrdinal.frameIndex = mOutIndex++; - outOrdinal.timestamp = mInputTimeUs; - cloneAndSend( - inputIndex, - work, - FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer)); - buffer.reset(); - } - if (outargs.numOutBytes > 0) { mInputSize = 0; int consumed = ((capacity / sizeof(int16_t)) - inargs.numInSamples); mInputTimeUs = work->input.ordinal.timestamp + (consumed * 1000000ll / channelCount / sampleRate); - buffer = createLinearBuffer(block, 0, outargs.numOutBytes); -#if defined(LOG_NDEBUG) && !LOG_NDEBUG - hexdump(outPtr, std::min(outargs.numOutBytes, 256)); -#endif - outPtr = temp; - outAvailable = 0; - block.reset(); } else { mInputSize += outargs.numInSamples * sizeof(int16_t); + mInputTimeUs += outargs.numInSamples * 1000000ll / channelCount / sampleRate; } + outPtr += outargs.numOutBytes; + nOutputBytes += outargs.numOutBytes; if (outargs.numInSamples > 0) { inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples; @@ -479,29 +433,15 @@ void C2SoftAacEnc::process( inargs.numInSamples -= outargs.numInSamples; } } - ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld", - encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll()); + ALOGV("encoderErr = %d nOutputBytes = %zu; mInputSize = %zu inargs.numInSamples = %d", + encoderErr, nOutputBytes, mInputSize, inargs.numInSamples); } if (eos && inBufferSize[0] > 0) { - if (numFrames && !block) { - C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; - // TODO: error handling, proper usage, etc. - c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block); - if (err != C2_OK) { - ALOGE("err = %d", err); - } - - wView.reset(new C2WriteView(block->map().get())); - outPtr = wView->data(); - outAvailable = wView->size(); - --numFrames; - } - memset(&outargs, 0, sizeof(outargs)); outBuffer[0] = outPtr; - outBufferSize[0] = outAvailable; + outBufferSize[0] = outAvailable - nOutputBytes; // Flush inargs.numInSamples = -1; @@ -511,12 +451,27 @@ void C2SoftAacEnc::process( &outBufDesc, &inargs, &outargs); + + nOutputBytes += outargs.numOutBytes; + } + + work->worklets.front()->output.flags = + (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0); + work->worklets.front()->output.buffers.clear(); + work->worklets.front()->output.ordinal = work->input.ordinal; + work->worklets.front()->output.ordinal.timestamp = timestamp; + work->workletsProcessed = 1u; + if (nOutputBytes) { + work->worklets.front()->output.buffers.push_back( + createLinearBuffer(block, 0, nOutputBytes)); } - outOrdinal.frameIndex = mOutIndex++; - outOrdinal.timestamp = mInputTimeUs; - FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0), - outOrdinal, buffer)(work); +#if 0 + ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", + nOutputBytes, mInputTimeUs.peekll(), outHeader->nFlags); + + hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); +#endif } c2_status_t C2SoftAacEnc::drain( diff --git a/media/codecs/aac/C2SoftAacEnc.h b/media/codecs/aac/C2SoftAacEnc.h index 82fb438..1e54638 100644 --- a/media/codecs/aac/C2SoftAacEnc.h +++ b/media/codecs/aac/C2SoftAacEnc.h @@ -17,8 +17,6 @@ #ifndef ANDROID_C2_SOFT_AAC_ENC_H_ #define ANDROID_C2_SOFT_AAC_ENC_H_ -#include <atomic> - #include <SimpleC2Component.h> #include "aacenc_lib.h" @@ -61,7 +59,6 @@ private: c2_cntr64_t mInputTimeUs; bool mSignalledError; - std::atomic_uint64_t mOutIndex; status_t initEncoder(); diff --git a/media/codecs/base/SimpleC2Component.cpp b/media/codecs/base/SimpleC2Component.cpp index 38ee673..d6a62a7 100644 --- a/media/codecs/base/SimpleC2Component.cpp +++ b/media/codecs/base/SimpleC2Component.cpp @@ -361,38 +361,14 @@ void SimpleC2Component::finish( } if (work) { fillWork(work); - std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener; + Mutexed<ExecState>::Locked state(mExecState); + std::shared_ptr<C2Component::Listener> listener = state->mListener; + state.unlock(); listener->onWorkDone_nb(shared_from_this(), vec(work)); ALOGV("returning pending work"); } } -void SimpleC2Component::cloneAndSend( - uint64_t frameIndex, - const std::unique_ptr<C2Work> ¤tWork, - std::function<void(const std::unique_ptr<C2Work> &)> fillWork) { - std::unique_ptr<C2Work> work(new C2Work); - if (currentWork->input.ordinal.frameIndex == frameIndex) { - work->input.flags = currentWork->input.flags; - work->input.ordinal = currentWork->input.ordinal; - } else { - Mutexed<PendingWork>::Locked pending(mPendingWork); - if (pending->count(frameIndex) == 0) { - ALOGW("unknown frame index: %" PRIu64, frameIndex); - return; - } - work->input.flags = pending->at(frameIndex)->input.flags; - work->input.ordinal = pending->at(frameIndex)->input.ordinal; - } - work->worklets.emplace_back(new C2Worklet); - if (work) { - fillWork(work); - std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener; - listener->onWorkDone_nb(shared_from_this(), vec(work)); - ALOGV("cloned and sending work"); - } -} - bool SimpleC2Component::processQueue() { std::unique_ptr<C2Work> work; uint64_t generation; diff --git a/media/codecs/base/include/SimpleC2Component.h b/media/codecs/base/include/SimpleC2Component.h index b3a98f4..e745dc5 100644 --- a/media/codecs/base/include/SimpleC2Component.h +++ b/media/codecs/base/include/SimpleC2Component.h @@ -121,24 +121,6 @@ protected: */ void finish(uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork); - /** - * Clone pending or current work and send the work back to client. - * - * This method will retrieve and clone the pending or current work according - * to |frameIndex| and feed the work into |fillWork| function. |fillWork| - * must be "non-blocking". Once |fillWork| returns the filled work will be - * returned to the client. - * - * \param[in] frameIndex the index of the work - * \param[in] currentWork the current work under processing - * \param[in] fillWork the function to fill the retrieved work. - */ - void cloneAndSend( - uint64_t frameIndex, - const std::unique_ptr<C2Work> ¤tWork, - std::function<void(const std::unique_ptr<C2Work> &)> fillWork); - - std::shared_ptr<C2Buffer> createLinearBuffer( const std::shared_ptr<C2LinearBlock> &block); diff --git a/media/sfplugin/CCodec.cpp b/media/sfplugin/CCodec.cpp index 3ae4bc6..baf9cb6 100644 --- a/media/sfplugin/CCodec.cpp +++ b/media/sfplugin/CCodec.cpp @@ -533,10 +533,6 @@ public: mCodec->onWorkQueued(eos); } - void onOutputBuffersChanged() override { - mCodec->mCallback->onOutputBuffersChanged(); - } - private: CCodec *mCodec; }; @@ -1298,10 +1294,6 @@ void CCodec::flush() { std::list<std::unique_ptr<C2Work>> flushedWork; c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork); - { - Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); - flushedWork.splice(flushedWork.end(), *queue); - } if (err != C2_OK) { // TODO: convert err into status_t mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); @@ -1548,10 +1540,7 @@ void CCodec::onMessageReceived(const sp<AMessage> &msg) { (new AMessage(kWhatWorkDone, this))->post(); } - if (work->worklets.empty() - || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE)) { - subQueuedWorkCount(1); - } + subQueuedWorkCount(1); // handle configuration changes in work done Mutexed<Config>::Locked config(mConfig); bool changed = false; diff --git a/media/sfplugin/CCodecBufferChannel.cpp b/media/sfplugin/CCodecBufferChannel.cpp index 9413cda..6e8bd90 100644 --- a/media/sfplugin/CCodecBufferChannel.cpp +++ b/media/sfplugin/CCodecBufferChannel.cpp @@ -169,7 +169,7 @@ public: * index and MediaCodecBuffer object. Returns false if registration * fails. */ - virtual status_t registerBuffer( + virtual bool registerBuffer( const std::shared_ptr<C2Buffer> &buffer, size_t *index, sp<MediaCodecBuffer> *clientBuffer) = 0; @@ -178,7 +178,7 @@ public: * Register codec specific data as a buffer to be consistent with * MediaCodec behavior. */ - virtual status_t registerCsd( + virtual bool registerCsd( const C2StreamCsdInfo::output * /* csd */, size_t * /* index */, sp<MediaCodecBuffer> * /* clientBuffer */) = 0; @@ -272,7 +272,7 @@ private: namespace { // TODO: get this info from component -const static size_t kMinInputBufferArraySize = 4; +const static size_t kMinInputBufferArraySize = 8; const static size_t kMaxPipelineCapacity = 18; const static size_t kChannelOutputDelay = 0; const static size_t kMinOutputBufferArraySize = kMaxPipelineCapacity + @@ -561,33 +561,25 @@ public: * \param match[in] a function to test whether the buffer matches the * criteria or not. * \return OK if successful, - * WOULD_BLOCK if slots are being used, - * NO_MEMORY if no slot matches the criteria, even though it's - * available + * NO_MEMORY if there's no available slot meets the criteria. */ status_t grabBuffer( size_t *index, sp<Codec2Buffer> *buffer, std::function<bool(const sp<Codec2Buffer> &)> match = [](const sp<Codec2Buffer> &) { return true; }) { - // allBuffersDontMatch remains true if all buffers are available but - // match() returns false for every buffer. - bool allBuffersDontMatch = true; for (size_t i = 0; i < mBuffers.size(); ++i) { - if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) { - if (match(mBuffers[i].clientBuffer)) { - mBuffers[i].ownedByClient = true; - *buffer = mBuffers[i].clientBuffer; - (*buffer)->meta()->clear(); - (*buffer)->setRange(0, (*buffer)->capacity()); - *index = i; - return OK; - } - } else { - allBuffersDontMatch = false; + if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired() + && match(mBuffers[i].clientBuffer)) { + mBuffers[i].ownedByClient = true; + *buffer = mBuffers[i].clientBuffer; + (*buffer)->meta()->clear(); + (*buffer)->setRange(0, (*buffer)->capacity()); + *index = i; + return OK; } } - return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK; + return NO_MEMORY; } /** @@ -671,14 +663,6 @@ public: } } - void realloc(std::function<sp<Codec2Buffer>()> alloc) { - size_t size = mBuffers.size(); - mBuffers.clear(); - for (size_t i = 0; i < size; ++i) { - mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false }); - } - } - private: std::string mImplName; ///< name for debugging const char *mName; ///< C-string version of name @@ -1054,7 +1038,7 @@ public: return nullptr; } - status_t registerBuffer( + bool registerBuffer( const std::shared_ptr<C2Buffer> &buffer, size_t *index, sp<MediaCodecBuffer> *clientBuffer) final { @@ -1065,25 +1049,22 @@ public: [buffer](const sp<Codec2Buffer> &clientBuffer) { return clientBuffer->canCopy(buffer); }); - if (err == WOULD_BLOCK) { - ALOGV("[%s] buffers temporarily not available", mName); - return err; - } else if (err != OK) { + if (err != OK) { ALOGD("[%s] grabBuffer failed: %d", mName, err); - return err; + return false; } c2Buffer->setFormat(mFormat); if (!c2Buffer->copy(buffer)) { ALOGD("[%s] copy buffer failed", mName); - return WOULD_BLOCK; + return false; } submit(c2Buffer); *clientBuffer = c2Buffer; ALOGV("[%s] grabbed buffer %zu", mName, *index); - return OK; + return true; } - status_t registerCsd( + bool registerCsd( const C2StreamCsdInfo::output *csd, size_t *index, sp<MediaCodecBuffer> *clientBuffer) final { @@ -1096,13 +1077,13 @@ public: && clientBuffer->capacity() >= csd->flexCount(); }); if (err != OK) { - return err; + return false; } memcpy(c2Buffer->base(), csd->m.value, csd->flexCount()); c2Buffer->setRange(0, csd->flexCount()); c2Buffer->setFormat(mFormat); *clientBuffer = c2Buffer; - return OK; + return true; } bool releaseBuffer( @@ -1122,36 +1103,6 @@ public: mImpl.getArray(array); } - void realloc(const std::shared_ptr<C2Buffer> &c2buffer) { - std::function<sp<Codec2Buffer>()> alloc; - switch (c2buffer->data().type()) { - case C2BufferData::LINEAR: { - uint32_t size = kLinearBufferSize; - const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front(); - if (block.size() < kMaxLinearBufferSize / 2) { - size = block.size() * 2; - } else { - size = kMaxLinearBufferSize; - } - alloc = [format = mFormat, size] { - return new LocalLinearBuffer(format, new ABuffer(size)); - }; - break; - } - - // TODO: add support - case C2BufferData::GRAPHIC: FALLTHROUGH_INTENDED; - - case C2BufferData::INVALID: FALLTHROUGH_INTENDED; - case C2BufferData::LINEAR_CHUNKS: FALLTHROUGH_INTENDED; - case C2BufferData::GRAPHIC_CHUNKS: FALLTHROUGH_INTENDED; - default: - ALOGD("Unsupported type: %d", (int)c2buffer->data().type()); - return; - } - mImpl.realloc(alloc); - } - private: BuffersArrayImpl mImpl; }; @@ -1162,7 +1113,7 @@ public: : OutputBuffers(componentName, name), mImpl(mName) { } - status_t registerBuffer( + bool registerBuffer( const std::shared_ptr<C2Buffer> &buffer, size_t *index, sp<MediaCodecBuffer> *clientBuffer) override { @@ -1171,10 +1122,10 @@ public: *index = mImpl.assignSlot(newBuffer); *clientBuffer = newBuffer; ALOGV("[%s] registered buffer %zu", mName, *index); - return OK; + return true; } - status_t registerCsd( + bool registerCsd( const C2StreamCsdInfo::output *csd, size_t *index, sp<MediaCodecBuffer> *clientBuffer) final { @@ -1182,7 +1133,7 @@ public: mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount())); *index = mImpl.assignSlot(newBuffer); *clientBuffer = newBuffer; - return OK; + return true; } bool releaseBuffer( @@ -1379,57 +1330,65 @@ void CCodecBufferChannel::QueueSync::stop() { // CCodecBufferChannel::PipelineCapacity CCodecBufferChannel::PipelineCapacity::PipelineCapacity() - : input(0), component(0), + : input(0), component(0), output(0), mName("<UNKNOWN COMPONENT>") { } void CCodecBufferChannel::PipelineCapacity::initialize( int newInput, int newComponent, + int newOutput, const char* newName, const char* callerTag) { input.store(newInput, std::memory_order_relaxed); component.store(newComponent, std::memory_order_relaxed); + output.store(newOutput, std::memory_order_relaxed); mName = newName; ALOGV("[%s] %s -- PipelineCapacity::initialize(): " "pipeline availability initialized ==> " - "input = %d, component = %d", + "input = %d, component = %d, output = %d", mName, callerTag ? callerTag : "*", - newInput, newComponent); + newInput, newComponent, newOutput); } bool CCodecBufferChannel::PipelineCapacity::allocate(const char* callerTag) { int prevInput = input.fetch_sub(1, std::memory_order_relaxed); int prevComponent = component.fetch_sub(1, std::memory_order_relaxed); - if (prevInput > 0 && prevComponent > 0) { + int prevOutput = output.fetch_sub(1, std::memory_order_relaxed); + if (prevInput > 0 && prevComponent > 0 && prevOutput > 0) { ALOGV("[%s] %s -- PipelineCapacity::allocate() returns true: " "pipeline availability -1 all ==> " - "input = %d, component = %d", + "input = %d, component = %d, output = %d", mName, callerTag ? callerTag : "*", prevInput - 1, - prevComponent - 1); + prevComponent - 1, + prevOutput - 1); return true; } input.fetch_add(1, std::memory_order_relaxed); component.fetch_add(1, std::memory_order_relaxed); + output.fetch_add(1, std::memory_order_relaxed); ALOGV("[%s] %s -- PipelineCapacity::allocate() returns false: " "pipeline availability unchanged ==> " - "input = %d, component = %d", + "input = %d, component = %d, output = %d", mName, callerTag ? callerTag : "*", prevInput, - prevComponent); + prevComponent, + prevOutput); return false; } void CCodecBufferChannel::PipelineCapacity::free(const char* callerTag) { int prevInput = input.fetch_add(1, std::memory_order_relaxed); int prevComponent = component.fetch_add(1, std::memory_order_relaxed); + int prevOutput = output.fetch_add(1, std::memory_order_relaxed); ALOGV("[%s] %s -- PipelineCapacity::free(): " "pipeline availability +1 all ==> " - "input = %d, component = %d", + "input = %d, component = %d, output = %d", mName, callerTag ? callerTag : "*", prevInput + 1, - prevComponent + 1); + prevComponent + 1, + prevOutput + 1); } int CCodecBufferChannel::PipelineCapacity::freeInputSlots( @@ -1439,12 +1398,13 @@ int CCodecBufferChannel::PipelineCapacity::freeInputSlots( std::memory_order_relaxed); ALOGV("[%s] %s -- PipelineCapacity::freeInputSlots(%zu): " "pipeline availability +%zu input ==> " - "input = %d, component = %d", + "input = %d, component = %d, output = %d", mName, callerTag ? callerTag : "*", numDiscardedInputBuffers, numDiscardedInputBuffers, prevInput + static_cast<int>(numDiscardedInputBuffers), - component.load(std::memory_order_relaxed)); + component.load(std::memory_order_relaxed), + output.load(std::memory_order_relaxed)); return prevInput + static_cast<int>(numDiscardedInputBuffers); } @@ -1453,84 +1413,25 @@ int CCodecBufferChannel::PipelineCapacity::freeComponentSlot( int prevComponent = component.fetch_add(1, std::memory_order_relaxed); ALOGV("[%s] %s -- PipelineCapacity::freeComponentSlot(): " "pipeline availability +1 component ==> " - "input = %d, component = %d", + "input = %d, component = %d, output = %d", mName, callerTag ? callerTag : "*", input.load(std::memory_order_relaxed), - prevComponent + 1); + prevComponent + 1, + output.load(std::memory_order_relaxed)); return prevComponent + 1; } -// CCodecBufferChannel::ReorderStash - -CCodecBufferChannel::ReorderStash::ReorderStash() { - clear(); -} - -void CCodecBufferChannel::ReorderStash::clear() { - mPending.clear(); - mStash.clear(); - mDepth = 0; - mKey = C2Config::ORDINAL; -} - -void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) { - mPending.splice(mPending.end(), mStash); - mDepth = depth; -} -void CCodecBufferChannel::ReorderStash::setKey(C2Config::ordinal_key_t key) { - mPending.splice(mPending.end(), mStash); - mKey = key; -} - -bool CCodecBufferChannel::ReorderStash::pop(Entry *entry) { - if (mPending.empty()) { - return false; - } - entry->buffer = mPending.front().buffer; - entry->timestamp = mPending.front().timestamp; - entry->flags = mPending.front().flags; - entry->ordinal = mPending.front().ordinal; - mPending.pop_front(); - return true; -} - -void CCodecBufferChannel::ReorderStash::emplace( - const std::shared_ptr<C2Buffer> &buffer, - int64_t timestamp, - int32_t flags, - const C2WorkOrdinalStruct &ordinal) { - for (auto it = mStash.begin(); it != mStash.end(); ++it) { - if (less(ordinal, it->ordinal)) { - mStash.emplace(it, buffer, timestamp, flags, ordinal); - return; - } - } - mStash.emplace_back(buffer, timestamp, flags, ordinal); - while (!mStash.empty() && mStash.size() > mDepth) { - mPending.push_back(mStash.front()); - mStash.pop_front(); - } -} - -void CCodecBufferChannel::ReorderStash::defer( - const CCodecBufferChannel::ReorderStash::Entry &entry) { - mPending.push_front(entry); -} - -bool CCodecBufferChannel::ReorderStash::hasPending() const { - return !mPending.empty(); -} - -bool CCodecBufferChannel::ReorderStash::less( - const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) { - switch (mKey) { - case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex; - case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp; - case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal; - default: - ALOGD("Unrecognized key; default to timestamp"); - return o1.frameIndex < o2.frameIndex; - } +int CCodecBufferChannel::PipelineCapacity::freeOutputSlot( + const char* callerTag) { + int prevOutput = output.fetch_add(1, std::memory_order_relaxed); + ALOGV("[%s] %s -- PipelineCapacity::freeOutputSlot(): " + "pipeline availability +1 output ==> " + "input = %d, component = %d, output = %d", + mName, callerTag ? callerTag : "*", + input.load(std::memory_order_relaxed), + component.load(std::memory_order_relaxed), + prevOutput + 1); + return prevOutput + 1; } // CCodecBufferChannel @@ -1772,7 +1673,6 @@ void CCodecBufferChannel::feedInputBufferIfAvailable() { void CCodecBufferChannel::feedInputBufferIfAvailableInternal() { while (!mInputMetEos && - !mReorderStash.lock()->hasPending() && mAvailablePipelineCapacity.allocate("feedInputBufferIfAvailable")) { sp<MediaCodecBuffer> inBuffer; size_t index; @@ -1791,6 +1691,8 @@ void CCodecBufferChannel::feedInputBufferIfAvailableInternal() { status_t CCodecBufferChannel::renderOutputBuffer( const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) { + mAvailablePipelineCapacity.freeOutputSlot("renderOutputBuffer"); + feedInputBufferIfAvailable(); std::shared_ptr<C2Buffer> c2Buffer; { Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); @@ -1801,7 +1703,6 @@ status_t CCodecBufferChannel::renderOutputBuffer( if (!c2Buffer) { return INVALID_OPERATION; } - sendOutputBuffers(); #if 0 const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info(); @@ -1942,12 +1843,11 @@ status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) { buffers.unlock(); released = true; + mAvailablePipelineCapacity.freeOutputSlot("discardBuffer"); } } - if (released) { - feedInputBufferIfAvailable(); - sendOutputBuffers(); - } else { + feedInputBufferIfAvailable(); + if (!released) { ALOGD("[%s] MediaCodec discarded an unknown buffer", mName); } return OK; @@ -1979,34 +1879,38 @@ status_t CCodecBufferChannel::start( const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) { C2StreamBufferTypeSetting::input iStreamFormat(0u); C2StreamBufferTypeSetting::output oStreamFormat(0u); - C2PortReorderBufferDepthTuning::output reorderDepth; - C2PortReorderKeySetting::output reorderKey; c2_status_t err = mComponent->query( - { - &iStreamFormat, - &oStreamFormat, - &reorderDepth, - &reorderKey, - }, + { &iStreamFormat, &oStreamFormat }, {}, C2_DONT_BLOCK, nullptr); - if (err == C2_BAD_INDEX) { - if (!iStreamFormat || !oStreamFormat) { - return UNKNOWN_ERROR; - } - Mutexed<ReorderStash>::Locked reorder(mReorderStash); - reorder->clear(); - if (reorderDepth) { - reorder->setDepth(reorderDepth.value); - } - if (reorderKey) { - reorder->setKey(reorderKey.value); - } - } else if (err != C2_OK) { + if (err != C2_OK) { return UNKNOWN_ERROR; } + // Query delays + C2PortRequestedDelayTuning::input inputDelay; + C2PortRequestedDelayTuning::output outputDelay; + C2RequestedPipelineDelayTuning pipelineDelay; +#if 0 + err = mComponent->query( + { &inputDelay, &pipelineDelay, &outputDelay }, + {}, + C2_DONT_BLOCK, + nullptr); + mAvailablePipelineCapacity.initialize( + inputDelay, + inputDelay + pipelineDelay, + inputDelay + pipelineDelay + outputDelay, + mName); +#else + mAvailablePipelineCapacity.initialize( + kMinInputBufferArraySize, + kMaxPipelineCapacity, + kMinOutputBufferArraySize, + mName); +#endif + // TODO: get this from input format bool secure = mComponent->getName().find(".secure") != std::string::npos; @@ -2246,33 +2150,6 @@ status_t CCodecBufferChannel::start( } } - // Set up pipeline control. This has to be done after mInputBuffers and - // mOutputBuffers are initialized to make sure that lingering callbacks - // about buffers from the previous generation do not interfere with the - // newly initialized pipeline capacity. - - // Query delays - C2PortRequestedDelayTuning::input inputDelay; - C2PortRequestedDelayTuning::output outputDelay; - C2RequestedPipelineDelayTuning pipelineDelay; -#if 0 - err = mComponent->query( - { &inputDelay, &pipelineDelay, &outputDelay }, - {}, - C2_DONT_BLOCK, - nullptr); - mAvailablePipelineCapacity.initialize( - inputDelay, - inputDelay + pipelineDelay, - inputDelay + pipelineDelay + outputDelay, - mName); -#else - mAvailablePipelineCapacity.initialize( - kMinInputBufferArraySize, - kMaxPipelineCapacity, - mName); -#endif - mInputMetEos = false; mSync.start(); return OK; @@ -2347,6 +2224,7 @@ status_t CCodecBufferChannel::requestInitialInputBuffers() { for (const sp<MediaCodecBuffer> &buffer : toBeQueued) { if (queueInputBufferInternal(buffer) != OK) { mAvailablePipelineCapacity.freeComponentSlot("requestInitialInputBuffers"); + mAvailablePipelineCapacity.freeOutputSlot("requestInitialInputBuffers"); } } return OK; @@ -2354,7 +2232,7 @@ status_t CCodecBufferChannel::requestInitialInputBuffers() { void CCodecBufferChannel::stop() { mSync.stop(); - mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed); + mFirstValidFrameIndex = mFrameIndex.load(); if (mInputSurface != nullptr) { mInputSurface->disconnect(); mInputSurface.reset(); @@ -2398,11 +2276,13 @@ void CCodecBufferChannel::onWorkDone( std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, const C2StreamInitDataInfo::output *initData, size_t numDiscardedInputBuffers) { + mAvailablePipelineCapacity.freeInputSlots(numDiscardedInputBuffers, + "onWorkDone"); + mAvailablePipelineCapacity.freeComponentSlot("onWorkDone"); if (handleWork(std::move(work), outputFormat, initData)) { - mAvailablePipelineCapacity.freeInputSlots(numDiscardedInputBuffers, - "onWorkDone"); - feedInputBufferIfAvailable(); + mAvailablePipelineCapacity.freeOutputSlot("onWorkDone"); } + feedInputBufferIfAvailable(); } void CCodecBufferChannel::onInputBufferDone( @@ -2411,11 +2291,9 @@ void CCodecBufferChannel::onInputBufferDone( { Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers); newInputSlotAvailable = (*buffers)->expireComponentBuffer(buffer); - if (newInputSlotAvailable) { - mAvailablePipelineCapacity.freeInputSlots(1, "onInputBufferDone"); - } } if (newInputSlotAvailable) { + mAvailablePipelineCapacity.freeInputSlots(1, "onInputBufferDone"); feedInputBufferIfAvailable(); } } @@ -2424,24 +2302,12 @@ bool CCodecBufferChannel::handleWork( std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, const C2StreamInitDataInfo::output *initData) { - if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) { - // Discard frames from previous generation. - ALOGD("[%s] Discard frames from previous generation.", mName); - return false; - } - - if (work->worklets.size() != 1u - || !work->worklets.front() - || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE)) { - mAvailablePipelineCapacity.freeComponentSlot("handleWork"); - } - - if (work->result == C2_NOT_FOUND) { - ALOGD("[%s] flushed work; ignored.", mName); - return true; - } - if (work->result != C2_OK) { + if (work->result == C2_NOT_FOUND) { + // TODO: Define what flushed work's result is. + ALOGD("[%s] flushed work; ignored.", mName); + return true; + } ALOGD("[%s] work failed to complete: %d", mName, work->result); mCCodecCallback->onError(work->result, ACTION_CODE_FATAL); return false; @@ -2456,7 +2322,11 @@ bool CCodecBufferChannel::handleWork( } const std::unique_ptr<C2Worklet> &worklet = work->worklets.front(); - + if ((worklet->output.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) { + // Discard frames from previous generation. + ALOGD("[%s] Discard frames from previous generation.", mName); + return true; + } std::shared_ptr<C2Buffer> buffer; // NOTE: MediaCodec usage supposedly have only one output stream. if (worklet->output.buffers.size() > 1u) { @@ -2471,40 +2341,6 @@ bool CCodecBufferChannel::handleWork( } } - while (!worklet->output.configUpdate.empty()) { - std::unique_ptr<C2Param> param; - worklet->output.configUpdate.back().swap(param); - worklet->output.configUpdate.pop_back(); - switch (param->coreIndex().coreIndex()) { - case C2PortReorderBufferDepthTuning::CORE_INDEX: { - C2PortReorderBufferDepthTuning::output reorderDepth; - if (reorderDepth.updateFrom(*param)) { - mReorderStash.lock()->setDepth(reorderDepth.value); - ALOGV("[%s] onWorkDone: updated reorder depth to %u", - mName, reorderDepth.value); - } else { - ALOGD("[%s] onWorkDone: failed to read reorder depth", mName); - } - break; - } - case C2PortReorderKeySetting::CORE_INDEX: { - C2PortReorderKeySetting::output reorderKey; - if (reorderKey.updateFrom(*param)) { - mReorderStash.lock()->setKey(reorderKey.value); - ALOGV("[%s] onWorkDone: updated reorder key to %u", - mName, reorderKey.value); - } else { - ALOGD("[%s] onWorkDone: failed to read reorder key", mName); - } - break; - } - default: - ALOGV("[%s] onWorkDone: unrecognized config update (%08X)", - mName, param->index()); - break; - } - } - if (outputFormat != nullptr) { Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); ALOGD("[%s] onWorkDone: output format changed to %s", @@ -2529,6 +2365,7 @@ bool CCodecBufferChannel::handleWork( ALOGV("[%s] onWorkDone: output EOS", mName); } + bool feedNeeded = true; sp<MediaCodecBuffer> outBuffer; size_t index; @@ -2550,7 +2387,7 @@ bool CCodecBufferChannel::handleWork( if (initData != nullptr) { Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); - if ((*buffers)->registerCsd(initData, &index, &outBuffer) == OK) { + if ((*buffers)->registerCsd(initData, &index, &outBuffer)) { outBuffer->meta()->setInt64("timeUs", timestamp.peek()); outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG); ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get()); @@ -2558,6 +2395,7 @@ bool CCodecBufferChannel::handleWork( buffers.unlock(); mCallback->onOutputBufferAvailable(index, outBuffer); buffers.lock(); + feedNeeded = false; } else { ALOGD("[%s] onWorkDone: unable to register csd", mName); buffers.unlock(); @@ -2570,7 +2408,7 @@ bool CCodecBufferChannel::handleWork( if (!buffer && !flags) { ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)", mName, work->input.ordinal.frameIndex.peekull()); - return true; + return feedNeeded; } if (buffer) { @@ -2589,53 +2427,23 @@ bool CCodecBufferChannel::handleWork( } { - Mutexed<ReorderStash>::Locked reorder(mReorderStash); - reorder->emplace(buffer, timestamp.peek(), flags, worklet->output.ordinal); - if (flags & MediaCodec::BUFFER_FLAG_EOS) { - // Flush reorder stash - reorder->setDepth(0); - } - } - sendOutputBuffers(); - return true; -} - -void CCodecBufferChannel::sendOutputBuffers() { - ReorderStash::Entry entry; - sp<MediaCodecBuffer> outBuffer; - size_t index; - - while (true) { - { - Mutexed<ReorderStash>::Locked reorder(mReorderStash); - if (!reorder->hasPending()) { - break; - } - if (!reorder->pop(&entry)) { - break; - } - } Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers); - status_t err = (*buffers)->registerBuffer(entry.buffer, &index, &outBuffer); - if (err != OK) { - if (err != WOULD_BLOCK) { - OutputBuffersArray *array = (OutputBuffersArray *)buffers->get(); - array->realloc(entry.buffer); - mCCodecCallback->onOutputBuffersChanged(); - } - buffers.unlock(); - ALOGV("[%s] sendOutputBuffers: unable to register output buffer", mName); - mReorderStash.lock()->defer(entry); - return; + if (!(*buffers)->registerBuffer(buffer, &index, &outBuffer)) { + ALOGD("[%s] onWorkDone: unable to register output buffer", mName); + // TODO + // buffers.unlock(); + // mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); + // buffers.lock(); + return false; } - buffers.unlock(); - - outBuffer->meta()->setInt64("timeUs", entry.timestamp); - outBuffer->meta()->setInt32("flags", entry.flags); - ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu", - mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size()); - mCallback->onOutputBufferAvailable(index, outBuffer); } + + outBuffer->meta()->setInt64("timeUs", timestamp.peek()); + outBuffer->meta()->setInt32("flags", flags); + ALOGV("[%s] onWorkDone: out buffer index = %zu [%p] => %p + %zu", + mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size()); + mCallback->onOutputBufferAvailable(index, outBuffer); + return false; } status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) { diff --git a/media/sfplugin/CCodecBufferChannel.h b/media/sfplugin/CCodecBufferChannel.h index bd199c2..8631235 100644 --- a/media/sfplugin/CCodecBufferChannel.h +++ b/media/sfplugin/CCodecBufferChannel.h @@ -43,7 +43,6 @@ public: virtual void onError(status_t err, enum ActionCode actionCode) = 0; virtual void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) = 0; virtual void onWorkQueued(bool eos) = 0; - virtual void onOutputBuffersChanged() = 0; }; /** @@ -218,7 +217,6 @@ private: bool handleWork( std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, const C2StreamInitDataInfo::output *initData); - void sendOutputBuffers(); QueueSync mSync; sp<MemoryDealer> mDealer; @@ -273,36 +271,44 @@ private: // CCodecBufferChannel whose outputs have not been returned from the // component (by calling onWorkDone()) does not exceed a certain limit. // (Let us call this the "component" capacity.) + // 3. The number of work items that have been received by + // CCodecBufferChannel whose outputs have not been released by the app + // (either by calling discardBuffer() on an output buffer or calling + // renderOutputBuffer()) does not exceed a certain limit. (Let us call + // this the "output" capacity.) // // These three criteria guarantee that a new input buffer that arrives from // the invocation of onInputBufferAvailable() will not // 1. overload CCodecBufferChannel's input buffers; // 2. overload the component; or + // 3. overload CCodecBufferChannel's output buffers if the component + // finishes all the pending work right away. // struct PipelineCapacity { // The number of available input capacity. std::atomic_int input; // The number of available component capacity. std::atomic_int component; + // The number of available output capacity. + std::atomic_int output; PipelineCapacity(); - // Set the values of #input and #component. - void initialize(int newInput, int newComponent, + // Set the values of #component and #output. + void initialize(int newInput, int newComponent, int newOutput, const char* newName = "<UNKNOWN COMPONENT>", const char* callerTag = nullptr); - // Return true and decrease #input and #component by one if + // Return true and decrease #input, #component and #output by one if // they are all greater than zero; return false otherwise. // // callerTag is used for logging only. // // allocate() is called by CCodecBufferChannel to check whether it can // receive another input buffer. If the return value is true, - // onInputBufferAvailable() and onOutputBufferAvailable() can be called - // afterwards. + // onInputBufferAvailable() can (and will) be called afterwards. bool allocate(const char* callerTag = nullptr); - // Increase #input and #component by one. + // Increase #input, #component and #output by one. // // callerTag is used for logging only. // @@ -329,52 +335,21 @@ private: // onWorkDone() is called. int freeComponentSlot(const char* callerTag = nullptr); + // Increase #output by one and return the updated value. + // + // callerTag is used for logging only. + // + // freeOutputSlot() is called by CCodecBufferChannel when + // discardBuffer() is called on an output buffer or when + // renderOutputBuffer() is called. + int freeOutputSlot(const char* callerTag = nullptr); + private: // Component name. Used for logging. const char* mName; }; PipelineCapacity mAvailablePipelineCapacity; - class ReorderStash { - public: - struct Entry { - inline Entry() : buffer(nullptr), timestamp(0), flags(0), ordinal({0, 0, 0}) {} - inline Entry( - const std::shared_ptr<C2Buffer> &b, - int64_t t, - int32_t f, - const C2WorkOrdinalStruct &o) - : buffer(b), timestamp(t), flags(f), ordinal(o) {} - std::shared_ptr<C2Buffer> buffer; - int64_t timestamp; - int32_t flags; - C2WorkOrdinalStruct ordinal; - }; - - ReorderStash(); - - void clear(); - void setDepth(uint32_t depth); - void setKey(C2Config::ordinal_key_t key); - bool pop(Entry *entry); - void emplace( - const std::shared_ptr<C2Buffer> &buffer, - int64_t timestamp, - int32_t flags, - const C2WorkOrdinalStruct &ordinal); - void defer(const Entry &entry); - bool hasPending() const; - - private: - std::list<Entry> mPending; - std::list<Entry> mStash; - uint32_t mDepth; - C2Config::ordinal_key_t mKey; - - bool less(const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2); - }; - Mutexed<ReorderStash> mReorderStash; - std::atomic_bool mInputMetEos; inline bool hasCryptoOrDescrambler() { |
