diff options
author | Pin-chih Lin <johnylin@google.com> | 2018-05-09 22:25:19 +0800 |
---|---|---|
committer | Pin-chih Lin <johnylin@google.com> | 2018-06-19 11:08:52 +0800 |
commit | 5ab2613e7d19c4b1f32b86e1274357c1f9dfba87 (patch) | |
tree | 85f9b38ca03d92c220bccd7396c94cf3ec9d6cee | |
parent | 448c0c7413335489520e89118c60041be684e9a3 (diff) | |
download | v4l2_codec2-5ab2613e7d19c4b1f32b86e1274357c1f9dfba87.tar.gz |
codec2: use temporal hack for buffer recycling in byte-buffer mode
This is not a proper solution!! Since we don't have one to recycle output
buffers in byte-buffer mode (no IGBP is given), we temporarily use an internal
mock queue for buffers outputted to client and recycle it when it is popped
from the queue by a new push.
Bug: 79239042
Test: CtsMediaTestCases android.media.cts.DecoderTest#testCodecResetsVP8WithoutSurface
Change-Id: I7b6778a3fbacc61eb0c1b9c741a749df3b6689d9
-rw-r--r-- | C2VDAComponent.cpp | 67 | ||||
-rw-r--r-- | include/C2VDAComponent.h | 7 | ||||
-rw-r--r-- | tests/C2VDACompIntf_test.cpp | 2 |
3 files changed, 58 insertions, 18 deletions
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp index 1f15e2d..80e2e81 100644 --- a/C2VDAComponent.cpp +++ b/C2VDAComponent.cpp @@ -58,6 +58,13 @@ const C2String kVP9DecoderName = "c2.vda.vp9.decoder"; const uint32_t kDpbOutputBufferExtraCount = 3; // Use the same number as ACodec. const int kDequeueRetryDelayUs = 10000; // Wait time of dequeue buffer retry in microseconds. +// Hack(b/79239042): Max size of mMockBufferQueueInClient. +// This value is empirically picked from previous CTS try-run. If this value is too big, it may +// cause VDA deadlock when it requires more buffers to decode and dequeue a new one. On the other +// hand, too small value may produce wrong display picture because recycling goes faster than +// rendering. +const size_t kMockMaxBuffersInClient = 5; + } // namespace C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper) @@ -140,7 +147,7 @@ C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2Reflec .build()); C2Allocator::id_t inputAllocators[] = {C2PlatformAllocatorStore::ION}; - C2Allocator::id_t outputAllocators[] = {C2PlatformAllocatorStore::GRALLOC}; + C2Allocator::id_t outputAllocators[] = {C2VDAAllocatorStore::V4L2_BUFFERQUEUE}; addParameter( DefineParam(mInputAllocatorIds, C2_PARAMKEY_INPUT_ALLOCATORS) @@ -203,6 +210,7 @@ C2VDAComponent::C2VDAComponent(C2String name, c2_node_id_t id, mComponentState(ComponentState::UNINITIALIZED), mDrainWithEOS(false), mLastOutputTimestamp(-1), + mSurfaceMode(true), mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN), mState(State::UNLOADED), mWeakThisFactory(this) { @@ -391,7 +399,18 @@ void C2VDAComponent::onOutputBufferDone(int32_t pictureBufferId, int32_t bitstre CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_ACCELERATOR); // Output buffer will be passed to client soon along with mListener->onWorkDone_nb(). info->mState = GraphicBlockInfo::State::OWNED_BY_CLIENT; - mBuffersInClient++; + if (mSurfaceMode) { + mBuffersInClient++; + } else { // byte-buffer mode + // Hack(b/79239042) + mMockBufferQueueInClient.push_back(info->mSlotId); + if (mMockBufferQueueInClient.size() > kMockMaxBuffersInClient) { + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferReturned, + ::base::Unretained(this), + mMockBufferQueueInClient.front())); + mMockBufferQueueInClient.pop_front(); + } + } // Attach output buffer to the work corresponded to bitstreamId. auto block = info->mGraphicBlock; @@ -543,6 +562,7 @@ void C2VDAComponent::onStopDone() { mGraphicBlocks.clear(); + mMockBufferQueueInClient.clear(); // Hack(b/79239042) stopDequeueThread(); mStopDoneEvent->Signal(); @@ -690,23 +710,32 @@ c2_status_t C2VDAComponent::allocateBuffersFromBlockAllocator(const media::Size& } } + mMockBufferQueueInClient.clear(); // Hack(b/79239042) stopDequeueThread(); mGraphicBlocks.clear(); - // Set requested buffer count to C2VdaBqBlockPool. - std::shared_ptr<C2VdaBqBlockPool> bqPool = - std::static_pointer_cast<C2VdaBqBlockPool>(mOutputBlockPool); - if (bqPool) { - err = bqPool->requestNewBufferSet(static_cast<uint32_t>(bufferCount)); - if (err != C2_OK) { - ALOGE("failed to set buffer count magic to block pool: %d", err); - reportError(err); - return err; + if (mOutputBlockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { + // Set requested buffer count to C2VdaBqBlockPool. + std::shared_ptr<C2VdaBqBlockPool> bqPool = + std::static_pointer_cast<C2VdaBqBlockPool>(mOutputBlockPool); + if (bqPool) { + err = bqPool->requestNewBufferSet(static_cast<int32_t>(bufferCount)); + if (err == C2_NO_INIT) { + ALOGD("No surface in block pool, output is byte-buffer mode..."); + mSurfaceMode = false; + } else if (err != C2_OK) { + ALOGE("failed to set buffer count magic to block pool: %d", err); + reportError(err); + return err; + } + } else { + ALOGE("static_pointer_cast C2VdaBqBlockPool failed..."); + reportError(C2_CORRUPTED); + return C2_CORRUPTED; } - } else { - ALOGE("Component only supports C2VdaBqBlockPool"); - reportError(C2_CORRUPTED); - return C2_CORRUPTED; + } else { // CCodec falls back to use C2BasicGraphicBlockPool + ALOGD("CCodec falls back to use C2BasicGraphicBlockPool..."); + mSurfaceMode = false; } for (size_t i = 0; i < bufferCount; ++i) { @@ -724,7 +753,7 @@ c2_status_t C2VDAComponent::allocateBuffersFromBlockAllocator(const media::Size& } mOutputFormat.mMinNumBuffers = bufferCount; - if (!startDequeueThread(size, pixelFormat)) { + if (mSurfaceMode && !startDequeueThread(size, pixelFormat)) { reportError(C2_CORRUPTED); return C2_CORRUPTED; } @@ -795,7 +824,11 @@ void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block) { info.mHandle = std::move(passedHandle); info.mPlanes = std::move(passedPlanes); - info.mSlotId = getSlotFromGraphicBlockHandle(info.mGraphicBlock->handle()); + if (mSurfaceMode) { + info.mSlotId = getSlotFromGraphicBlockHandle(info.mGraphicBlock->handle()); + } else { // byte-buffer mode + info.mSlotId = static_cast<uint32_t>(info.mBlockId); + } mGraphicBlocks.push_back(std::move(info)); } diff --git a/include/C2VDAComponent.h b/include/C2VDAComponent.h index 53fcf4e..ed711c9 100644 --- a/include/C2VDAComponent.h +++ b/include/C2VDAComponent.h @@ -284,6 +284,13 @@ private: int64_t mLastOutputTimestamp; // The pointer of output block pool. std::shared_ptr<C2BlockPool> mOutputBlockPool; + // Hack(b/79239042): We do not have a solution to recycle buffers in byte-buffer mode now. This + // is a fake buffer queue to record buffers outputted to client, and regard buffer is returned + // when it is popped by a new push of the queue (size: kMockMaxBuffersInClient). + // TODO: provide proper solution and get rid of this hack. + std::list<uint32_t> mMockBufferQueueInClient; + // The indicator of whether output has surface. + bool mSurfaceMode; // The following members should be utilized on parent thread. diff --git a/tests/C2VDACompIntf_test.cpp b/tests/C2VDACompIntf_test.cpp index 6ed0753..aea52b2 100644 --- a/tests/C2VDACompIntf_test.cpp +++ b/tests/C2VDACompIntf_test.cpp @@ -30,7 +30,7 @@ const char* MEDIA_MIMETYPE_VIDEO_RAW = "video/raw"; const char* MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; const C2Allocator::id_t kInputAllocators[] = {C2PlatformAllocatorStore::ION}; -const C2Allocator::id_t kOutputAllocators[] = {C2PlatformAllocatorStore::GRALLOC}; +const C2Allocator::id_t kOutputAllocators[] = {C2PlatformAllocatorStore::V4L2_BUFFERQUEUE}; const C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_GRAPHIC; class C2VDACompIntfTest : public ::testing::Test { |