Revert "CCodecBufferChannel: Process output format when registering buffer"
This reverts commit b18c1afb550ab5bfdfac93f6dd921831edf8dbaf.
Reason for revert: Camera regression
Bug: 149751672
Fixes: 155145653
Test: manual
Change-Id: I52ddd8fb974f8952fb1e63d5da0075be9144136d
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index e2be991..6b389d5 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -127,6 +127,97 @@
count->value = -1;
}
+// CCodecBufferChannel::ReorderStash
+
+CCodecBufferChannel::ReorderStash::ReorderStash() {
+ clear();
+}
+
+void CCodecBufferChannel::ReorderStash::clear() {
+ mPending.clear();
+ mStash.clear();
+ mDepth = 0;
+ mKey = C2Config::ORDINAL;
+}
+
+void CCodecBufferChannel::ReorderStash::flush() {
+ mPending.clear();
+ mStash.clear();
+}
+
+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) {
+ bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
+ if (!buffer && eos) {
+ // TRICKY: we may be violating ordering of the stash here. Because we
+ // don't expect any more emplace() calls after this, the ordering should
+ // not matter.
+ mStash.emplace_back(buffer, timestamp, flags, ordinal);
+ } else {
+ flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
+ auto it = mStash.begin();
+ for (; it != mStash.end(); ++it) {
+ if (less(ordinal, it->ordinal)) {
+ break;
+ }
+ }
+ mStash.emplace(it, buffer, timestamp, flags, ordinal);
+ if (eos) {
+ mStash.back().flags = mStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
+ }
+ }
+ 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;
+ }
+}
+
// Input
CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
@@ -616,7 +707,7 @@
void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
if (mInputMetEos ||
- mOutput.lock()->buffers->hasPending() ||
+ mReorderStash.lock()->hasPending() ||
mPipelineWatcher.lock()->pipelineFull()) {
return;
} else {
@@ -889,6 +980,17 @@
return UNKNOWN_ERROR;
}
+ {
+ Mutexed<ReorderStash>::Locked reorder(mReorderStash);
+ reorder->clear();
+ if (reorderDepth) {
+ reorder->setDepth(reorderDepth.value);
+ }
+ if (reorderKey) {
+ reorder->setKey(reorderKey.value);
+ }
+ }
+
uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
@@ -1157,13 +1259,6 @@
}
output->buffers->setFormat(outputFormat);
- output->buffers->clearStash();
- if (reorderDepth) {
- output->buffers->setReorderDepth(reorderDepth.value);
- }
- if (reorderKey) {
- output->buffers->setReorderKey(reorderKey.value);
- }
// Try to set output surface to created block pool if given.
if (outputSurface) {
@@ -1331,8 +1426,8 @@
{
Mutexed<Output>::Locked output(mOutput);
output->buffers->flush(flushedWork);
- output->buffers->flushStash();
}
+ mReorderStash.lock()->flush();
mPipelineWatcher.lock()->flush();
}
@@ -1368,34 +1463,45 @@
std::unique_ptr<C2Work> work,
const sp<AMessage> &outputFormat,
const C2StreamInitDataInfo::output *initData) {
- // Whether the output buffer should be reported to the client or not.
- bool notifyClient = false;
+ if (outputFormat != nullptr) {
+ Mutexed<Output>::Locked output(mOutput);
+ ALOGD("[%s] onWorkDone: output format changed to %s",
+ mName, outputFormat->debugString().c_str());
+ output->buffers->setFormat(outputFormat);
- if (work->result == C2_OK){
- notifyClient = true;
- } else if (work->result == C2_NOT_FOUND) {
- ALOGD("[%s] flushed work; ignored.", mName);
- } else {
- // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
- // the config update.
- ALOGD("[%s] work failed to complete: %d", mName, work->result);
- mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
- return false;
+ AString mediaType;
+ if (outputFormat->findString(KEY_MIME, &mediaType)
+ && mediaType == MIMETYPE_AUDIO_RAW) {
+ int32_t channelCount;
+ int32_t sampleRate;
+ if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
+ && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
+ output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
+ }
+ }
}
- if ((work->input.ordinal.frameIndex -
- mFirstValidFrameIndex.load()).peek() < 0) {
+ if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
// Discard frames from previous generation.
ALOGD("[%s] Discard frames from previous generation.", mName);
- notifyClient = false;
+ return false;
}
if (mInputSurface == nullptr && (work->worklets.size() != 1u
|| !work->worklets.front()
- || !(work->worklets.front()->output.flags &
- C2FrameData::FLAG_INCOMPLETE))) {
- mPipelineWatcher.lock()->onWorkDone(
- work->input.ordinal.frameIndex.peeku());
+ || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE))) {
+ mPipelineWatcher.lock()->onWorkDone(work->input.ordinal.frameIndex.peeku());
+ }
+
+ if (work->result == C2_NOT_FOUND) {
+ ALOGD("[%s] flushed work; ignored.", mName);
+ return true;
+ }
+
+ if (work->result != C2_OK) {
+ ALOGD("[%s] work failed to complete: %d", mName, work->result);
+ mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
+ return false;
}
// NOTE: MediaCodec usage supposedly have only one worklet
@@ -1431,10 +1537,8 @@
case C2PortReorderBufferDepthTuning::CORE_INDEX: {
C2PortReorderBufferDepthTuning::output reorderDepth;
if (reorderDepth.updateFrom(*param)) {
- bool secure = mComponent->getName().find(".secure") !=
- std::string::npos;
- mOutput.lock()->buffers->setReorderDepth(
- reorderDepth.value);
+ bool secure = mComponent->getName().find(".secure") != std::string::npos;
+ mReorderStash.lock()->setDepth(reorderDepth.value);
ALOGV("[%s] onWorkDone: updated reorder depth to %u",
mName, reorderDepth.value);
size_t numOutputSlots = mOutput.lock()->numSlots;
@@ -1446,19 +1550,17 @@
output->maxDequeueBuffers += numInputSlots;
}
if (output->surface) {
- output->surface->setMaxDequeuedBufferCount(
- output->maxDequeueBuffers);
+ output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
}
} else {
- ALOGD("[%s] onWorkDone: failed to read reorder depth",
- mName);
+ ALOGD("[%s] onWorkDone: failed to read reorder depth", mName);
}
break;
}
case C2PortReorderKeySetting::CORE_INDEX: {
C2PortReorderKeySetting::output reorderKey;
if (reorderKey.updateFrom(*param)) {
- mOutput.lock()->buffers->setReorderKey(reorderKey.value);
+ mReorderStash.lock()->setKey(reorderKey.value);
ALOGV("[%s] onWorkDone: updated reorder key to %u",
mName, reorderKey.value);
} else {
@@ -1473,8 +1575,7 @@
ALOGV("[%s] onWorkDone: updating pipeline delay %u",
mName, pipelineDelay.value);
newPipelineDelay = pipelineDelay.value;
- (void)mPipelineWatcher.lock()->pipelineDelay(
- pipelineDelay.value);
+ (void)mPipelineWatcher.lock()->pipelineDelay(pipelineDelay.value);
}
}
if (param->forInput()) {
@@ -1483,8 +1584,7 @@
ALOGV("[%s] onWorkDone: updating input delay %u",
mName, inputDelay.value);
newInputDelay = inputDelay.value;
- (void)mPipelineWatcher.lock()->inputDelay(
- inputDelay.value);
+ (void)mPipelineWatcher.lock()->inputDelay(inputDelay.value);
}
}
if (param->forOutput()) {
@@ -1492,10 +1592,8 @@
if (outputDelay.updateFrom(*param)) {
ALOGV("[%s] onWorkDone: updating output delay %u",
mName, outputDelay.value);
- bool secure = mComponent->getName().find(".secure") !=
- std::string::npos;
- (void)mPipelineWatcher.lock()->outputDelay(
- outputDelay.value);
+ bool secure = mComponent->getName().find(".secure") != std::string::npos;
+ (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
bool outputBuffersChanged = false;
size_t numOutputSlots = 0;
@@ -1503,8 +1601,7 @@
{
Mutexed<Output>::Locked output(mOutput);
output->outputDelay = outputDelay.value;
- numOutputSlots = outputDelay.value +
- kSmoothnessFactor;
+ numOutputSlots = outputDelay.value + kSmoothnessFactor;
if (output->numSlots < numOutputSlots) {
output->numSlots = numOutputSlots;
if (output->buffers->isArrayMode()) {
@@ -1523,7 +1620,7 @@
mCCodecCallback->onOutputBuffersChanged();
}
- uint32_t depth = mOutput.lock()->buffers->getReorderDepth();
+ uint32_t depth = mReorderStash.lock()->depth();
Mutexed<OutputSurface>::Locked output(mOutputSurface);
output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
if (!secure) {
@@ -1567,6 +1664,9 @@
ALOGV("[%s] onWorkDone: output EOS", mName);
}
+ sp<MediaCodecBuffer> outBuffer;
+ size_t index;
+
// WORKAROUND: adjust output timestamp based on client input timestamp and codec
// input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
// the codec input timestamp, but client output timestamp should (reported in timeUs)
@@ -1587,18 +1687,8 @@
worklet->output.ordinal.timestamp.peekll(),
timestamp.peekll());
- // csd cannot be re-ordered and will always arrive first.
if (initData != nullptr) {
Mutexed<Output>::Locked output(mOutput);
- if (outputFormat) {
- output->buffers->updateSkipCutBuffer(outputFormat);
- output->buffers->setFormat(outputFormat);
- }
- if (!notifyClient) {
- return false;
- }
- size_t index;
- sp<MediaCodecBuffer> outBuffer;
if (output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
outBuffer->meta()->setInt64("timeUs", timestamp.peek());
outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG);
@@ -1614,10 +1704,10 @@
}
}
- if (notifyClient && !buffer && !flags) {
+ if (!buffer && !flags) {
ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
mName, work->input.ordinal.frameIndex.peekull());
- notifyClient = false;
+ return true;
}
if (buffer) {
@@ -1636,60 +1726,63 @@
}
{
- Mutexed<Output>::Locked output(mOutput);
- output->buffers->pushToStash(
- buffer,
- notifyClient,
- timestamp.peek(),
- flags,
- outputFormat,
- worklet->output.ordinal);
+ 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() {
- OutputBuffers::BufferAction action;
- size_t index;
+ ReorderStash::Entry entry;
sp<MediaCodecBuffer> outBuffer;
- std::shared_ptr<C2Buffer> c2Buffer;
+ size_t index;
while (true) {
+ Mutexed<ReorderStash>::Locked reorder(mReorderStash);
+ if (!reorder->hasPending()) {
+ break;
+ }
+ if (!reorder->pop(&entry)) {
+ break;
+ }
+
Mutexed<Output>::Locked output(mOutput);
- action = output->buffers->popFromStashAndRegister(
- &c2Buffer, &index, &outBuffer);
- switch (action) {
- case OutputBuffers::SKIP:
- return;
- case OutputBuffers::DISCARD:
- break;
- case OutputBuffers::NOTIFY_CLIENT:
- output.unlock();
- mCallback->onOutputBufferAvailable(index, outBuffer);
- break;
- case OutputBuffers::REALLOCATE: {
+ status_t err = output->buffers->registerBuffer(entry.buffer, &index, &outBuffer);
+ if (err != OK) {
+ bool outputBuffersChanged = false;
+ if (err != WOULD_BLOCK) {
if (!output->buffers->isArrayMode()) {
- output->buffers =
- output->buffers->toArrayMode(output->numSlots);
+ output->buffers = output->buffers->toArrayMode(output->numSlots);
}
- static_cast<OutputBuffersArray*>(output->buffers.get())->
- realloc(c2Buffer);
- output.unlock();
+ OutputBuffersArray *array = (OutputBuffersArray *)output->buffers.get();
+ array->realloc(entry.buffer);
+ outputBuffersChanged = true;
+ }
+ ALOGV("[%s] sendOutputBuffers: unable to register output buffer", mName);
+ reorder->defer(entry);
+
+ output.unlock();
+ reorder.unlock();
+
+ if (outputBuffersChanged) {
mCCodecCallback->onOutputBuffersChanged();
}
return;
- case OutputBuffers::RETRY:
- ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
- mName);
- return;
- default:
- LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
- "corrupted BufferAction value (%d) "
- "returned from popFromStashAndRegister.",
- mName, int(action));
- return;
}
+ output.unlock();
+ reorder.unlock();
+
+ outBuffer->meta()->setInt64("timeUs", entry.timestamp);
+ outBuffer->meta()->setInt32("flags", entry.flags);
+ ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu (%lld)",
+ mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size(),
+ (long long)entry.timestamp);
+ mCallback->onOutputBufferAvailable(index, outBuffer);
}
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index da15724..0263211 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -296,6 +296,48 @@
Mutexed<PipelineWatcher> mPipelineWatcher;
+ 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 flush();
+ 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;
+ uint32_t depth() const { return mDepth; }
+
+ 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;
std::once_flag mRenderWarningFlag;
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 4ce13aa..d7cc175 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -21,7 +21,6 @@
#include <C2PlatformSupport.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/SkipCutBuffer.h>
@@ -150,29 +149,16 @@
setSkipCutBuffer(delay, padding);
}
-void OutputBuffers::updateSkipCutBuffer(
- const sp<AMessage> &format, bool notify) {
- AString mediaType;
- if (format->findString(KEY_MIME, &mediaType)
- && mediaType == MIMETYPE_AUDIO_RAW) {
- int32_t channelCount;
- int32_t sampleRate;
- if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
- && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
- updateSkipCutBuffer(sampleRate, channelCount);
- }
- }
- if (notify) {
- mUnreportedFormat = nullptr;
- }
-}
-
void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
if (mSkipCutBuffer != nullptr) {
mSkipCutBuffer->submit(buffer);
}
}
+void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
+ mSkipCutBuffer = scb;
+}
+
void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
if (mSkipCutBuffer != nullptr) {
size_t prevSize = mSkipCutBuffer->size();
@@ -183,175 +169,6 @@
mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
}
-void OutputBuffers::clearStash() {
- mPending.clear();
- mReorderStash.clear();
- mDepth = 0;
- mKey = C2Config::ORDINAL;
- mUnreportedFormat = nullptr;
-}
-
-void OutputBuffers::flushStash() {
- for (StashEntry& e : mPending) {
- e.notify = false;
- }
- for (StashEntry& e : mReorderStash) {
- e.notify = false;
- }
-}
-
-uint32_t OutputBuffers::getReorderDepth() const {
- return mDepth;
-}
-
-void OutputBuffers::setReorderDepth(uint32_t depth) {
- mPending.splice(mPending.end(), mReorderStash);
- mDepth = depth;
-}
-
-void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
- mPending.splice(mPending.end(), mReorderStash);
- mKey = key;
-}
-
-void OutputBuffers::pushToStash(
- const std::shared_ptr<C2Buffer>& buffer,
- bool notify,
- int64_t timestamp,
- int32_t flags,
- const sp<AMessage>& format,
- const C2WorkOrdinalStruct& ordinal) {
- bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
- if (!buffer && eos) {
- // TRICKY: we may be violating ordering of the stash here. Because we
- // don't expect any more emplace() calls after this, the ordering should
- // not matter.
- mReorderStash.emplace_back(
- buffer, notify, timestamp, flags, format, ordinal);
- } else {
- flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
- auto it = mReorderStash.begin();
- for (; it != mReorderStash.end(); ++it) {
- if (less(ordinal, it->ordinal)) {
- break;
- }
- }
- mReorderStash.emplace(it,
- buffer, notify, timestamp, flags, format, ordinal);
- if (eos) {
- mReorderStash.back().flags =
- mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
- }
- }
- while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
- mPending.push_back(mReorderStash.front());
- mReorderStash.pop_front();
- }
- ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
-}
-
-OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
- std::shared_ptr<C2Buffer>* c2Buffer,
- size_t* index,
- sp<MediaCodecBuffer>* outBuffer) {
- if (mPending.empty()) {
- return SKIP;
- }
-
- // Retrieve the first entry.
- StashEntry &entry = mPending.front();
-
- *c2Buffer = entry.buffer;
- sp<AMessage> outputFormat = entry.format;
-
- // The output format can be processed without a registered slot.
- if (outputFormat) {
- ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
- mName, outputFormat->debugString().c_str());
- updateSkipCutBuffer(outputFormat, entry.notify);
- }
-
- if (entry.notify) {
- if (outputFormat) {
- setFormat(outputFormat);
- } else if (mUnreportedFormat) {
- outputFormat = mUnreportedFormat->dup();
- setFormat(outputFormat);
- }
- mUnreportedFormat = nullptr;
- } else {
- if (outputFormat) {
- mUnreportedFormat = outputFormat;
- } else if (!mUnreportedFormat) {
- mUnreportedFormat = mFormat;
- }
- }
-
- // Flushing mReorderStash because no other buffers should come after output
- // EOS.
- if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
- // Flush reorder stash
- setReorderDepth(0);
- }
-
- if (!entry.notify) {
- mPending.pop_front();
- return DISCARD;
- }
-
- // Try to register the buffer.
- status_t err = registerBuffer(*c2Buffer, index, outBuffer);
- if (err != OK) {
- if (err != WOULD_BLOCK) {
- return REALLOCATE;
- }
- return RETRY;
- }
-
- // Append information from the front stash entry to outBuffer.
- (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
- (*outBuffer)->meta()->setInt32("flags", entry.flags);
- ALOGV("[%s] popFromStashAndRegister: "
- "out buffer index = %zu [%p] => %p + %zu (%lld)",
- mName, *index, outBuffer->get(),
- (*outBuffer)->data(), (*outBuffer)->size(),
- (long long)entry.timestamp);
-
- // The front entry of mPending will be removed now that the registration
- // succeeded.
- mPending.pop_front();
- return NOTIFY_CLIENT;
-}
-
-bool OutputBuffers::popPending(StashEntry *entry) {
- if (mPending.empty()) {
- return false;
- }
- *entry = mPending.front();
- mPending.pop_front();
- return true;
-}
-
-void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
- mPending.push_front(entry);
-}
-
-bool OutputBuffers::hasPending() const {
- return !mPending.empty();
-}
-
-bool OutputBuffers::less(
- const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
- 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;
- }
-}
-
// LocalBufferPool
std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
@@ -1151,16 +968,6 @@
mImpl.grow(newSize, mAlloc);
}
-void OutputBuffersArray::transferFrom(OutputBuffers* source) {
- mFormat = source->mFormat;
- mSkipCutBuffer = source->mSkipCutBuffer;
- mUnreportedFormat = source->mUnreportedFormat;
- mPending = std::move(source->mPending);
- mReorderStash = std::move(source->mReorderStash);
- mDepth = source->mDepth;
- mKey = source->mKey;
-}
-
// FlexOutputBuffers
status_t FlexOutputBuffers::registerBuffer(
@@ -1203,12 +1010,13 @@
// track of the flushed work.
}
-std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
+std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
- array->transferFrom(this);
+ array->setFormat(mFormat);
+ array->transferSkipCutBuffer(mSkipCutBuffer);
std::function<sp<Codec2Buffer>()> alloc = getAlloc();
array->initialize(mImpl, size, alloc);
- return array;
+ return std::move(array);
}
size_t FlexOutputBuffers::numClientBuffers() const {
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index cadc4d8..85ca5d5 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -154,8 +154,6 @@
DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
};
-class OutputBuffersArray;
-
class OutputBuffers : public CCodecBuffers {
public:
OutputBuffers(const char *componentName, const char *name = "Output")
@@ -164,12 +162,8 @@
/**
* Register output C2Buffer from the component and obtain corresponding
- * index and MediaCodecBuffer object.
- *
- * Returns:
- * OK if registration succeeds.
- * NO_MEMORY if all buffers are available but not compatible.
- * WOULD_BLOCK if there are compatible buffers, but they are all in use.
+ * index and MediaCodecBuffer object. Returns false if registration
+ * fails.
*/
virtual status_t registerBuffer(
const std::shared_ptr<C2Buffer> &buffer,
@@ -204,7 +198,7 @@
* shall retain the internal state so that it will honor index and
* buffer from previous calls of registerBuffer().
*/
- virtual std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) = 0;
+ virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
/**
* Initialize SkipCutBuffer object.
@@ -213,164 +207,6 @@
int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount);
/**
- * Update SkipCutBuffer from format. The @p format must not be null.
- * @p notify determines whether the format comes with a buffer that should
- * be reported to the client or not.
- */
- void updateSkipCutBuffer(const sp<AMessage> &format, bool notify = true);
-
- /**
- * Output Stash
- * ============
- *
- * The output stash is a place to hold output buffers temporarily before
- * they are registered to output slots. It has 2 main functions:
- * 1. Allow reordering of output frames as the codec may produce frames in a
- * different order.
- * 2. Act as a "buffer" between the codec and the client because the codec
- * may produce more buffers than available slots. This excess of codec's
- * output buffers should be registered to slots later, after the client
- * has released some slots.
- *
- * The stash consists of 2 lists of buffers: mPending and mReorderStash.
- * mPending is a normal FIFO queue with not size limit, while mReorderStash
- * is a sorted list with size limit mDepth.
- *
- * The normal flow of a non-csd output buffer is as follows:
- *
- * |----------------OutputBuffers---------------|
- * |----------Output stash----------| |
- * Codec --|-> mReorderStash --> mPending --|-> slots --|-> client
- * | | |
- * pushToStash() popFromStashAndRegister()
- *
- * The buffer that comes from the codec first enters mReorderStash. The
- * first buffer in mReorderStash gets moved to mPending when mReorderStash
- * overflows. Buffers in mPending are registered to slots and given to the
- * client as soon as slots are available.
- *
- * Every output buffer that is not a csd buffer should be put on the stash
- * by calling pushToStash(), then later registered to a slot by calling
- * popFromStashAndRegister() before notifying the client with
- * onOutputBufferAvailable().
- *
- * Reordering
- * ==========
- *
- * mReorderStash is a sorted list with a specified size limit. The size
- * limit can be set by calling setReorderDepth().
- *
- * Every buffer in mReorderStash has a C2WorkOrdinalStruct, which contains 3
- * members, all of which are comparable. Which member of C2WorkOrdinalStruct
- * should be used for reordering can be chosen by calling setReorderKey().
- */
-
- /**
- * Return the reorder depth---the size of mReorderStash.
- */
- uint32_t getReorderDepth() const;
-
- /**
- * Set the reorder depth.
- */
- void setReorderDepth(uint32_t depth);
-
- /**
- * Set the type of "key" to use in comparisons.
- */
- void setReorderKey(C2Config::ordinal_key_t key);
-
- /**
- * Return whether the output stash has any pending buffers.
- */
- bool hasPending() const;
-
- /**
- * Flush the stash and reset the depth and the key to their default values.
- */
- void clearStash();
-
- /**
- * Flush the stash.
- */
- void flushStash();
-
- /**
- * Push a buffer to the reorder stash.
- *
- * @param buffer C2Buffer object from the returned work.
- * @param notify Whether the returned work contains a buffer that should
- * be reported to the client. This may be false if the
- * caller wants to process the buffer without notifying the
- * client.
- * @param timestamp Buffer timestamp to report to the client.
- * @param flags Buffer flags to report to the client.
- * @param format Buffer format to report to the client.
- * @param ordinal Ordinal used in reordering. This determines when the
- * buffer will be popped from the output stash by
- * `popFromStashAndRegister()`.
- */
- void pushToStash(
- const std::shared_ptr<C2Buffer>& buffer,
- bool notify,
- int64_t timestamp,
- int32_t flags,
- const sp<AMessage>& format,
- const C2WorkOrdinalStruct& ordinal);
-
- enum BufferAction : int {
- SKIP,
- DISCARD,
- NOTIFY_CLIENT,
- REALLOCATE,
- RETRY,
- };
-
- /**
- * Try to atomically pop the first buffer from the reorder stash and
- * register it to an output slot. The function returns a value that
- * indicates a recommended course of action for the caller.
- *
- * If the stash is empty, the function will return `SKIP`.
- *
- * If the stash is not empty, the function will peek at the first (oldest)
- * entry in mPending process the buffer in the entry as follows:
- * - If the buffer should not be sent to the client, the function will
- * return `DISCARD`. The stash entry will be removed.
- * - If the buffer should be sent to the client, the function will attempt
- * to register the buffer to a slot. The registration may have 3 outcomes
- * corresponding to the following return values:
- * - `NOTIFY_CLIENT`: The buffer is successfully registered to a slot. The
- * output arguments @p index and @p outBuffer will contain valid values
- * that the caller can use to call onOutputBufferAvailable(). The stash
- * entry will be removed.
- * - `REALLOCATE`: The buffer is not registered because it is not
- * compatible with the current slots (which are available). The caller
- * should reallocate the OutputBuffers with slots that can fit the
- * returned @p c2Buffer. The stash entry will not be removed
- * - `RETRY`: All slots are currently occupied by the client. The caller
- * should try to call this function again after the client has released
- * some slots.
- *
- * @return What the caller should do afterwards.
- *
- * @param[out] c2Buffer Underlying C2Buffer associated to the first buffer
- * on the stash. This value is guaranteed to be valid
- * unless the return value is `SKIP`.
- * @param[out] index Slot index. This value is valid only if the return
- * value is `NOTIFY_CLIENT`.
- * @param[out] outBuffer Registered buffer. This value is valid only if the
- * return valu is `NOTIFY_CLIENT`.
- */
- BufferAction popFromStashAndRegister(
- std::shared_ptr<C2Buffer>* c2Buffer,
- size_t* index,
- sp<MediaCodecBuffer>* outBuffer);
-
-protected:
- sp<SkipCutBuffer> mSkipCutBuffer;
-
- /**
* Update the SkipCutBuffer object. No-op if it's never initialized.
*/
void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount);
@@ -380,8 +216,15 @@
*/
void submit(const sp<MediaCodecBuffer> &buffer);
+ /**
+ * Transfer SkipCutBuffer object to the other Buffers object.
+ */
+ void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb);
+
+protected:
+ sp<SkipCutBuffer> mSkipCutBuffer;
+
private:
- // SkipCutBuffer
int32_t mDelay;
int32_t mPadding;
int32_t mSampleRate;
@@ -389,78 +232,7 @@
void setSkipCutBuffer(int32_t skip, int32_t cut);
- // Output stash
-
- // Output format that has not been made available to the client.
- sp<AMessage> mUnreportedFormat;
-
- // Struct for an entry in the output stash (mPending and mReorderStash)
- struct StashEntry {
- inline StashEntry()
- : buffer(nullptr),
- notify(false),
- timestamp(0),
- flags(0),
- format(),
- ordinal({0, 0, 0}) {}
- inline StashEntry(
- const std::shared_ptr<C2Buffer> &b,
- bool n,
- int64_t t,
- int32_t f,
- const sp<AMessage> &fmt,
- const C2WorkOrdinalStruct &o)
- : buffer(b),
- notify(n),
- timestamp(t),
- flags(f),
- format(fmt),
- ordinal(o) {}
- std::shared_ptr<C2Buffer> buffer;
- bool notify;
- int64_t timestamp;
- int32_t flags;
- sp<AMessage> format;
- C2WorkOrdinalStruct ordinal;
- };
-
- /**
- * FIFO queue of stash entries.
- */
- std::list<StashEntry> mPending;
- /**
- * Sorted list of stash entries.
- */
- std::list<StashEntry> mReorderStash;
- /**
- * Size limit of mReorderStash.
- */
- uint32_t mDepth{0};
- /**
- * Choice of key to use in ordering of stash entries in mReorderStash.
- */
- C2Config::ordinal_key_t mKey{C2Config::ORDINAL};
-
- /**
- * Return false if mPending is empty; otherwise, pop the first entry from
- * mPending and return true.
- */
- bool popPending(StashEntry *entry);
-
- /**
- * Push an entry as the first entry of mPending.
- */
- void deferPending(const StashEntry &entry);
-
- /**
- * Comparison of C2WorkOrdinalStruct based on mKey.
- */
- bool less(const C2WorkOrdinalStruct &o1,
- const C2WorkOrdinalStruct &o2) const;
-
DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
-
- friend OutputBuffersArray;
};
/**
@@ -1000,7 +772,7 @@
bool isArrayMode() const final { return true; }
- std::unique_ptr<OutputBuffersArray> toArrayMode(size_t) final {
+ std::unique_ptr<OutputBuffers> toArrayMode(size_t) final {
return nullptr;
}
@@ -1039,12 +811,6 @@
*/
void grow(size_t newSize);
- /**
- * Transfer the SkipCutBuffer and the output stash from another
- * OutputBuffers.
- */
- void transferFrom(OutputBuffers* source);
-
private:
BuffersArrayImpl mImpl;
std::function<sp<Codec2Buffer>()> mAlloc;
@@ -1073,7 +839,7 @@
void flush(
const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
- std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) override;
+ std::unique_ptr<OutputBuffers> toArrayMode(size_t size) override;
size_t numClientBuffers() const final;