diff options
author | Xin Li <delphij@google.com> | 2018-08-13 13:01:07 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2018-08-13 13:01:07 -0700 |
commit | 0f533897fc8962dc33527aeb8bd527c53e395d33 (patch) | |
tree | 68f51b308590ec57e6ce7d323ab0bd8efdb2403b | |
parent | baf051157883a64feda3d83043c555d0db592393 (diff) | |
parent | c8933181f5c09efb5527a1da7cda2fa7b4337f17 (diff) | |
download | v4l2_codec2-0f533897fc8962dc33527aeb8bd527c53e395d33.tar.gz |
Merge stage-dr1-aosp-master into stage-aosp-master
Bug: 112535855
Change-Id: I63787a77e44d5f49e31aa9c8b67d25329b821574
-rw-r--r-- | Android.bp | 32 | ||||
-rw-r--r-- | Android.mk | 4 | ||||
-rw-r--r-- | C2ArcVideoAcceleratorFactory.cpp | 87 | ||||
-rw-r--r-- | C2VDAAdaptorProxy.cpp | 2 | ||||
-rw-r--r-- | C2VDAComponent.cpp | 369 | ||||
-rw-r--r-- | include/C2ArcVideoAcceleratorFactory.h | 37 | ||||
-rw-r--r-- | include/C2VDAComponent.h | 63 | ||||
-rw-r--r-- | tests/Android.mk | 1 | ||||
-rw-r--r-- | tests/C2VDACompIntf_test.cpp | 3 |
9 files changed, 307 insertions, 291 deletions
diff --git a/Android.bp b/Android.bp deleted file mode 100644 index db4d39f..0000000 --- a/Android.bp +++ /dev/null @@ -1,32 +0,0 @@ -cc_library_shared { - name: "libv4l2_codec2_arcva_factory", - vendor_available: true, - product_variables: { - arc: { - srcs: ["C2ArcVideoAcceleratorFactory.cpp"], - - shared_libs: [ - "libarcbridge", - "libarcbridgeservice", - "libarcvideobridge", - "libbinder", - "libchrome", - "liblog", - "libmojo", - "libutils", - ], - - // -Wno-unused-parameter is needed for libchrome/base codes - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - "-std=c++14", - ], - }, - }, - clang: true, - export_include_dirs: [ - "include", - ], -} @@ -29,6 +29,8 @@ LOCAL_SHARED_LIBRARIES := libbinder \ liblog \ libmedia \ libstagefright \ + libstagefright_bufferqueue_helper \ + libstagefright_ccodec_ext \ libstagefright_codec2 \ libstagefright_codec2_vndk \ libstagefright_simple_c2component \ @@ -55,7 +57,7 @@ LOCAL_SRC_FILES := $(filter-out C2VDAAdaptor.cpp, $(LOCAL_SRC_FILES)) LOCAL_SHARED_LIBRARIES += libarcbridge \ libarcbridgeservice \ libmojo \ - libv4l2_codec2_arcva_factory \ + libcodec2_arcva_factory \ endif # ifneq (,$(findstring cheets_,$(TARGET_PRODUCT))) diff --git a/C2ArcVideoAcceleratorFactory.cpp b/C2ArcVideoAcceleratorFactory.cpp deleted file mode 100644 index 07997d1..0000000 --- a/C2ArcVideoAcceleratorFactory.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// #define LOG_NDEBUG 0 -#define LOG_TAG "C2ArcVideoAcceleratorFactory" - -#include <C2ArcVideoAcceleratorFactory.h> - -#include <base/bind.h> -#include <binder/IServiceManager.h> -#include <mojo/edk/embedder/embedder.h> -#include <mojo/public/cpp/bindings/interface_request.h> -#include <mojo/public/cpp/system/handle.h> -#include <utils/Log.h> - -namespace android { - -ANDROID_SINGLETON_STATIC_INSTANCE(C2ArcVideoAcceleratorFactory) - -bool C2ArcVideoAcceleratorFactory::createVideoDecodeAccelerator( - ::arc::mojom::VideoDecodeAcceleratorRequest request) { - if (!mRemoteFactory) { - ALOGE("Factory is not ready"); - return false; - } - mRemoteFactory->CreateDecodeAccelerator(std::move(request)); - return true; -} - -bool C2ArcVideoAcceleratorFactory::createVideoEncodeAccelerator( - ::arc::mojom::VideoEncodeAcceleratorRequest request) { - if (!mRemoteFactory) { - ALOGE("Factory is not ready"); - return false; - } - mRemoteFactory->CreateEncodeAccelerator(std::move(request)); - return true; -} - -bool C2ArcVideoAcceleratorFactory::createVideoProtectedBufferAllocator( - ::arc::mojom::VideoProtectedBufferAllocatorRequest request) { - if (!mRemoteFactory) { - ALOGE("Factory is not ready"); - return false; - } - mRemoteFactory->CreateProtectedBufferAllocator(std::move(request)); - return true; -} - -int32_t C2ArcVideoAcceleratorFactory::hostVersion() const { - return mHostVersion; -} - -C2ArcVideoAcceleratorFactory::C2ArcVideoAcceleratorFactory() : mHostVersion(0) { - sp<IBinder> binder = - defaultServiceManager()->getService(String16("android.os.IArcVideoBridge")); - if (binder == nullptr) { - ALOGE("Failed to find IArcVideoBridge service"); - return; - } - mArcVideoBridge = interface_cast<IArcVideoBridge>(binder); - mHostVersion = mArcVideoBridge->hostVersion(); - if (mHostVersion < 4) { - ALOGW("HostVersion(%d) is outdated", mHostVersion); - return; - } - - ALOGV("HostVersion: %d", mHostVersion); - - ::arc::MojoBootstrapResult bootstrapResult = - mArcVideoBridge->bootstrapVideoAcceleratorFactory(); - if (!bootstrapResult.is_valid()) { - ALOGE("bootstrapVideoAcceleratorFactory returns invalid result"); - return; - } - mojo::edk::ScopedPlatformHandle handle( - mojo::edk::PlatformHandle(bootstrapResult.releaseFd().release())); - ALOGV("SetParentPipeHandle(fd=%d)", handle.get().handle); - mojo::edk::SetParentPipeHandle(std::move(handle)); - mojo::ScopedMessagePipeHandle server_pipe = - mojo::edk::CreateChildMessagePipe(bootstrapResult.releaseToken()); - mRemoteFactory.Bind(mojo::InterfacePtrInfo<::arc::mojom::VideoAcceleratorFactory>( - std::move(server_pipe), 7u)); -} - -} // namespace android diff --git a/C2VDAAdaptorProxy.cpp b/C2VDAAdaptorProxy.cpp index 2c44e6b..4c493d1 100644 --- a/C2VDAAdaptorProxy.cpp +++ b/C2VDAAdaptorProxy.cpp @@ -64,7 +64,7 @@ bool C2VDAAdaptorProxy::establishChannel() { } void C2VDAAdaptorProxy::establishChannelOnMojoThread(std::shared_ptr<::arc::Future<bool>> future) { - C2ArcVideoAcceleratorFactory& factory = ::android::C2ArcVideoAcceleratorFactory::getInstance(); + auto& factory = ::android::GetC2ArcVideoAcceleratorFactory(); if (!factory.createVideoDecodeAccelerator(mojo::MakeRequest(&mVDAPtr))) { future->set(false); diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp index 2b3abde..5eec1ef 100644 --- a/C2VDAComponent.cpp +++ b/C2VDAComponent.cpp @@ -12,11 +12,14 @@ #endif #define __C2_GENERATE_GLOBAL_VARS__ +#include <C2VDAAllocatorStore.h> +#include <C2VdaBqBlockPool.h> #include <C2VDAComponent.h> #include <C2VDASupport.h> // to getParamReflector from vda store #include <videodev2.h> +#include <C2AllocatorGralloc.h> #include <C2ComponentFactory.h> #include <C2PlatformSupport.h> @@ -52,6 +55,16 @@ const C2String kH264DecoderName = "c2.vda.avc.decoder"; const C2String kVP8DecoderName = "c2.vda.vp8.decoder"; 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) @@ -134,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) @@ -170,28 +183,6 @@ C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2Reflec CHECK_NE(mComponentState, ComponentState::UNINITIALIZED); \ } while (0) -class C2VDAGraphicBuffer : public C2Buffer { -public: - C2VDAGraphicBuffer(const std::shared_ptr<C2GraphicBlock>& block, const media::Rect& visibleRect, - const base::Closure& releaseCB); - ~C2VDAGraphicBuffer() override; - -private: - base::Closure mReleaseCB; -}; - -C2VDAGraphicBuffer::C2VDAGraphicBuffer(const std::shared_ptr<C2GraphicBlock>& block, - const media::Rect& visibleRect, - const base::Closure& releaseCB) - : C2Buffer({block->share(C2Rect(visibleRect.width(), visibleRect.height()), C2Fence())}), - mReleaseCB(releaseCB) {} - -C2VDAGraphicBuffer::~C2VDAGraphicBuffer() { - if (!mReleaseCB.is_null()) { - mReleaseCB.Run(); - } -} - C2VDAComponent::VideoFormat::VideoFormat(HalPixelFormat pixelFormat, uint32_t minNumBuffers, media::Size codedSize, media::Rect visibleRect) : mPixelFormat(pixelFormat), @@ -199,15 +190,27 @@ C2VDAComponent::VideoFormat::VideoFormat(HalPixelFormat pixelFormat, uint32_t mi mCodedSize(codedSize), mVisibleRect(visibleRect) {} +static uint32_t getSlotFromGraphicBlockHandle(const C2Handle* const handle) { + uint32_t width, height, format, stride, igbp_slot, generation; + uint64_t usage, igbp_id; + _UnwrapNativeCodec2GrallocMetadata( + handle, &width, &height, &format, &usage, &stride, &generation, &igbp_id, &igbp_slot); + ALOGV("Unwrap Metadata: igbp[%" PRIu64 ", %u] (%u*%u, fmt %#x, usage %" PRIx64 ", stride %u)", + igbp_id, igbp_slot, width, height, format, usage, stride); + return igbp_slot; +} + C2VDAComponent::C2VDAComponent(C2String name, c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper>& helper) : mIntfImpl(std::make_shared<IntfImpl>(name, helper)), mIntf(std::make_shared<SimpleInterface<IntfImpl>>(name.c_str(), id, mIntfImpl)), mThread("C2VDAComponentThread"), + mDequeueThread("C2VDAComponentDequeueThread"), mVDAInitResult(VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE), mComponentState(ComponentState::UNINITIALIZED), - mDrainWithEOS(false), + mPendingOutputEOS(false), mLastOutputTimestamp(-1), + mSurfaceMode(true), mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN), mState(State::UNLOADED), mWeakThisFactory(this) { @@ -229,7 +232,7 @@ C2VDAComponent::~C2VDAComponent() { if (mThread.IsRunning()) { mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onDestroy, base::Unretained(this))); + ::base::Bind(&C2VDAComponent::onDestroy, ::base::Unretained(this))); mThread.Stop(); } } @@ -241,9 +244,10 @@ void C2VDAComponent::onDestroy() { mVDAAdaptor->destroy(); mVDAAdaptor.reset(nullptr); } + stopDequeueThread(); } -void C2VDAComponent::onStart(media::VideoCodecProfile profile, base::WaitableEvent* done) { +void C2VDAComponent::onStart(media::VideoCodecProfile profile, ::base::WaitableEvent* done) { DCHECK(mTaskRunner->BelongsToCurrentThread()); ALOGV("onStart"); CHECK_EQ(mComponentState, ComponentState::UNINITIALIZED); @@ -269,8 +273,6 @@ void C2VDAComponent::onQueueWork(std::unique_ptr<C2Work> work) { ALOGV("onQueueWork: flags=0x%x, index=%llu, timestamp=%llu", work->input.flags, work->input.ordinal.frameIndex.peekull(), work->input.ordinal.timestamp.peekull()); EXPECT_RUNNING_OR_RETURN_ON_ERROR(); - // It is illegal for client to put new works while component is still flushing. - CHECK_NE(mComponentState, ComponentState::FLUSHING); uint32_t drainMode = NO_DRAIN; if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { @@ -280,7 +282,7 @@ void C2VDAComponent::onQueueWork(std::unique_ptr<C2Work> work) { // TODO(johnylin): set a maximum size of mQueue and check if mQueue is already full. mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onDequeueWork, base::Unretained(this))); + ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); } void C2VDAComponent::onDequeueWork() { @@ -290,8 +292,9 @@ void C2VDAComponent::onDequeueWork() { if (mQueue.empty()) { return; } - if (mComponentState == ComponentState::DRAINING) { - ALOGV("Temporarily stop dequeueing works since component is draining."); + if (mComponentState == ComponentState::DRAINING || + mComponentState == ComponentState::FLUSHING) { + ALOGV("Temporarily stop dequeueing works since component is draining/flushing."); return; } if (mComponentState != ComponentState::STARTED) { @@ -304,10 +307,15 @@ void C2VDAComponent::onDequeueWork() { auto drainMode = mQueue.front().mDrainMode; mQueue.pop(); - CHECK_EQ(work->input.buffers.size(), 1u); - C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front(); - // linearBlock.size() == 0 means this is a dummy work. No decode needed. - if (linearBlock.size() > 0) { + CHECK_LE(work->input.buffers.size(), 1u); + if (work->input.buffers.empty()) { + // Client may queue an EOS work with no input buffer, otherwise every work must have one + // input buffer. + CHECK(drainMode != NO_DRAIN); + } else { + // If input.buffers is not empty, the buffer should have meaningful content inside. + C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front(); + CHECK_GT(linearBlock.size(), 0u); // Send input buffer to VDA for decode. // Use frameIndex as bitstreamId. int32_t bitstreamId = frameIndexToBitstreamId(work->input.ordinal.frameIndex); @@ -322,15 +330,15 @@ void C2VDAComponent::onDequeueWork() { if (drainMode != NO_DRAIN) { mVDAAdaptor->flush(); mComponentState = ComponentState::DRAINING; - mDrainWithEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; + mPendingOutputEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; } // Put work to mPendingWorks. mPendingWorks.emplace_back(std::move(work)); if (!mQueue.empty()) { - mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onDequeueWork, base::Unretained(this))); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onDequeueWork, + ::base::Unretained(this))); } } @@ -351,16 +359,9 @@ void C2VDAComponent::onInputBufferDone(int32_t bitstreamId) { reportFinishedWorkIfAny(); } -// This is used as callback while output buffer is released by client. -// TODO(johnylin): consider to use C2Buffer::registerOnDestroyNotify instead -void C2VDAComponent::returnOutputBuffer(int32_t pictureBufferId) { - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onOutputBufferReturned, - base::Unretained(this), pictureBufferId)); -} - -void C2VDAComponent::onOutputBufferReturned(int32_t pictureBufferId) { +void C2VDAComponent::onOutputBufferReturned(uint32_t slotId) { DCHECK(mTaskRunner->BelongsToCurrentThread()); - ALOGV("onOutputBufferReturned: picture id=%d", pictureBufferId); + ALOGV("onOutputBufferReturned: slot id=%u", slotId); if (mComponentState == ComponentState::UNINITIALIZED) { // Output buffer is returned from client after component is stopped. Just let the buffer be // released. @@ -369,7 +370,7 @@ void C2VDAComponent::onOutputBufferReturned(int32_t pictureBufferId) { // TODO(johnylin): when buffer is returned, we should confirm that output format is not changed // yet. If changed, just let the buffer be released. - GraphicBlockInfo* info = getGraphicBlockById(pictureBufferId); + GraphicBlockInfo* info = getGraphicBlockBySlot(slotId); if (!info) { reportError(C2_CORRUPTED); return; @@ -402,15 +403,28 @@ 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; + 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. - work->worklets.front()->output.buffers.emplace_back(std::make_shared<C2VDAGraphicBuffer>( - info->mGraphicBlock, mOutputFormat.mVisibleRect, - base::Bind(&C2VDAComponent::returnOutputBuffer, mWeakThisFactory.GetWeakPtr(), - pictureBufferId))); + auto block = info->mGraphicBlock; + work->worklets.front()->output.buffers.emplace_back(C2Buffer::CreateGraphicBuffer( + block->share(C2Rect(mOutputFormat.mVisibleRect.width(), + mOutputFormat.mVisibleRect.height()), + C2Fence()))); // TODO: this does not work for timestamps as they can wrap around - int64_t currentTimestamp = base::checked_cast<int64_t>(work->input.ordinal.timestamp.peek()); + int64_t currentTimestamp = ::base::checked_cast<int64_t>(work->input.ordinal.timestamp.peek()); CHECK_GE(currentTimestamp, mLastOutputTimestamp); mLastOutputTimestamp = currentTimestamp; @@ -434,7 +448,7 @@ void C2VDAComponent::onDrain(uint32_t drainMode) { if (mComponentState == ComponentState::STARTED) { mVDAAdaptor->flush(); mComponentState = ComponentState::DRAINING; - mDrainWithEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; + mPendingOutputEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; } else { ALOGV("Neglect drain. Component in state: %d", mComponentState); } @@ -452,13 +466,15 @@ void C2VDAComponent::onDrainDone() { } else if (mComponentState == ComponentState::STOPPING) { // The client signals stop right before VDA notifies drain done. Let stop process goes. return; - } else { + } else if (mComponentState != ComponentState::FLUSHING) { + // It is reasonable to get onDrainDone in FLUSHING, which means flush is already signaled + // and component should still expect onFlushDone callback from VDA. ALOGE("Unexpected state while onDrainDone(). State=%d", mComponentState); reportError(C2_BAD_STATE); return; } - if (mDrainWithEOS) { + if (mPendingOutputEOS) { // Return EOS work. reportEOSWork(); } @@ -470,27 +486,28 @@ void C2VDAComponent::onDrainDone() { // Work dequeueing was stopped while component draining. Restart it. mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onDequeueWork, base::Unretained(this))); + ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); } void C2VDAComponent::onFlush() { DCHECK(mTaskRunner->BelongsToCurrentThread()); ALOGV("onFlush"); - if (mComponentState == ComponentState::FLUSHING) { - return; // Ignore other flush request when component is flushing. + if (mComponentState == ComponentState::FLUSHING || + mComponentState == ComponentState::STOPPING) { + return; // Ignore other flush request when component is flushing or stopping. } - EXPECT_STATE_OR_RETURN_ON_ERROR(STARTED); + EXPECT_RUNNING_OR_RETURN_ON_ERROR(); mVDAAdaptor->reset(); - // Pop all works in mQueue and put into mPendingWorks. + // Pop all works in mQueue and put into mAbandonedWorks. while (!mQueue.empty()) { - mPendingWorks.emplace_back(std::move(mQueue.front().mWork)); + mAbandonedWorks.emplace_back(std::move(mQueue.front().mWork)); mQueue.pop(); } mComponentState = ComponentState::FLUSHING; } -void C2VDAComponent::onStop(base::WaitableEvent* done) { +void C2VDAComponent::onStop(::base::WaitableEvent* done) { DCHECK(mTaskRunner->BelongsToCurrentThread()); ALOGV("onStop"); EXPECT_RUNNING_OR_RETURN_ON_ERROR(); @@ -501,9 +518,9 @@ void C2VDAComponent::onStop(base::WaitableEvent* done) { mVDAAdaptor->reset(); } - // Pop all works in mQueue and put into mPendingWorks. + // Pop all works in mQueue and put into mAbandonedWorks. while (!mQueue.empty()) { - mPendingWorks.emplace_back(std::move(mQueue.front().mWork)); + mAbandonedWorks.emplace_back(std::move(mQueue.front().mWork)); mQueue.pop(); } @@ -531,15 +548,16 @@ void C2VDAComponent::onFlushDone() { // Reset the timestamp record. mLastOutputTimestamp = -1; mComponentState = ComponentState::STARTED; + + // Work dequeueing was stopped while component flushing. Restart it. + mTaskRunner->PostTask(FROM_HERE, + ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); } void C2VDAComponent::onStopDone() { ALOGV("onStopDone"); CHECK(mStopDoneEvent); - // Release the graphic block allocator object. - mOutputBlockPool.reset(); - // TODO(johnylin): At this moment, there may be C2Buffer still owned by client, do we need to // do something for them? reportAbandonedWorks(); @@ -552,6 +570,9 @@ void C2VDAComponent::onStopDone() { mGraphicBlocks.clear(); + mMockBufferQueueInClient.clear(); // Hack(b/79239042) + stopDequeueThread(); + mStopDoneEvent->Signal(); mStopDoneEvent = nullptr; mComponentState = ComponentState::UNINITIALIZED; @@ -606,6 +627,19 @@ C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockById(int32_t bl return &mGraphicBlocks[blockId]; } +C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockBySlot(uint32_t slotId) { + auto blockIter = std::find_if(mGraphicBlocks.begin(), mGraphicBlocks.end(), + [slotId](const GraphicBlockInfo& gb) { + return gb.mSlotId == slotId; + }); + + if (blockIter == mGraphicBlocks.end()) { + ALOGE("getGraphicBlockBySlot failed: slot=%u", slotId); + return nullptr; + } + return &(*blockIter); +} + void C2VDAComponent::onOutputFormatChanged(std::unique_ptr<VideoFormat> format) { DCHECK(mTaskRunner->BelongsToCurrentThread()); ALOGV("onOutputFormatChanged"); @@ -666,30 +700,55 @@ c2_status_t C2VDAComponent::allocateBuffersFromBlockAllocator(const media::Size& uint32_t pixelFormat) { ALOGV("allocateBuffersFromBlockAllocator(%s, 0x%x)", size.ToString().c_str(), pixelFormat); + mMockBufferQueueInClient.clear(); // Hack(b/79239042) + stopDequeueThread(); + size_t bufferCount = mOutputFormat.mMinNumBuffers + kDpbOutputBufferExtraCount; // Allocate the output buffers. mVDAAdaptor->assignPictureBuffers(bufferCount); // Get block pool ID configured from the client. + std::shared_ptr<C2BlockPool> blockPool; auto poolId = mIntfImpl->getBlockPoolId(); ALOGI("Using C2BlockPool ID = %" PRIu64 " for allocating output buffers", poolId); - c2_status_t err; - if (!mOutputBlockPool || mOutputBlockPool->getLocalId() != poolId) { - err = GetCodec2BlockPool(poolId, shared_from_this(), &mOutputBlockPool); - if (err != C2_OK) { - ALOGE("Graphic block allocator is invalid"); - reportError(err); - return err; - } + auto err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool); + if (err != C2_OK) { + ALOGE("Graphic block allocator is invalid"); + reportError(err); + return err; } mGraphicBlocks.clear(); + + if (blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { + // Set requested buffer count to C2VdaBqBlockPool. + std::shared_ptr<C2VdaBqBlockPool> bqPool = + std::static_pointer_cast<C2VdaBqBlockPool>(blockPool); + 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 { // CCodec falls back to use C2BasicGraphicBlockPool + ALOGD("CCodec falls back to use C2BasicGraphicBlockPool..."); + mSurfaceMode = false; + } + for (size_t i = 0; i < bufferCount; ++i) { std::shared_ptr<C2GraphicBlock> block; C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, 0}; - err = mOutputBlockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, - &block); + err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, &block); if (err != C2_OK) { mGraphicBlocks.clear(); ALOGE("failed to allocate buffer: %d", err); @@ -699,6 +758,11 @@ c2_status_t C2VDAComponent::allocateBuffersFromBlockAllocator(const media::Size& appendOutputBuffer(std::move(block)); } mOutputFormat.mMinNumBuffers = bufferCount; + + if (mSurfaceMode && !startDequeueThread(size, pixelFormat, std::move(blockPool))) { + reportError(C2_CORRUPTED); + return C2_CORRUPTED; + } return C2_OK; } @@ -752,7 +816,7 @@ void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block) { #endif ALOGV("HAL pixel format: 0x%x", static_cast<uint32_t>(info.mPixelFormat)); - base::ScopedFD passedHandle(dup(info.mGraphicBlock->handle()->data[0])); + ::base::ScopedFD passedHandle(dup(info.mGraphicBlock->handle()->data[0])); if (!passedHandle.is_valid()) { ALOGE("Failed to dup(%d), errno=%d", info.mGraphicBlock->handle()->data[0], errno); reportError(C2_CORRUPTED); @@ -766,6 +830,12 @@ void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block) { info.mHandle = std::move(passedHandle); info.mPlanes = std::move(passedPlanes); + 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)); } @@ -808,8 +878,8 @@ c2_status_t C2VDAComponent::queue_nb(std::list<std::unique_ptr<C2Work>>* const i } while (!items->empty()) { mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onQueueWork, base::Unretained(this), - base::Passed(&items->front()))); + ::base::Bind(&C2VDAComponent::onQueueWork, ::base::Unretained(this), + ::base::Passed(&items->front()))); items->pop_front(); } return C2_OK; @@ -828,7 +898,8 @@ c2_status_t C2VDAComponent::flush_sm(flush_mode_t mode, if (mState.load() != State::RUNNING) { return C2_BAD_STATE; } - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onFlush, base::Unretained(this))); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onFlush, + ::base::Unretained(this))); // Instead of |flushedWork|, abandoned works will be returned via onWorkDone_nb() callback. return C2_OK; } @@ -840,8 +911,9 @@ c2_status_t C2VDAComponent::drain_nb(drain_mode_t mode) { if (mState.load() != State::RUNNING) { return C2_BAD_STATE; } - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onDrain, base::Unretained(this), - static_cast<uint32_t>(mode))); + mTaskRunner->PostTask(FROM_HERE, + ::base::Bind(&C2VDAComponent::onDrain, ::base::Unretained(this), + static_cast<uint32_t>(mode))); return C2_OK; } @@ -856,10 +928,11 @@ c2_status_t C2VDAComponent::start() { mCodecProfile = mIntfImpl->getCodecProfile(); ALOGI("get parameter: mCodecProfile = %d", static_cast<int>(mCodecProfile)); - base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onStart, base::Unretained(this), - mCodecProfile, &done)); + ::base::WaitableEvent done(::base::WaitableEvent::ResetPolicy::AUTOMATIC, + ::base::WaitableEvent::InitialState::NOT_SIGNALED); + mTaskRunner->PostTask(FROM_HERE, + ::base::Bind(&C2VDAComponent::onStart, ::base::Unretained(this), + mCodecProfile, &done)); done.Wait(); if (mVDAInitResult != VideoDecodeAcceleratorAdaptor::Result::SUCCESS) { ALOGE("Failed to start component due to VDA error: %d", static_cast<int>(mVDAInitResult)); @@ -878,10 +951,10 @@ c2_status_t C2VDAComponent::stop() { return C2_OK; // Component is already in stopped state. } - base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); + ::base::WaitableEvent done(::base::WaitableEvent::ResetPolicy::AUTOMATIC, + ::base::WaitableEvent::InitialState::NOT_SIGNALED); mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onStop, base::Unretained(this), &done)); + ::base::Bind(&C2VDAComponent::onStop, ::base::Unretained(this), &done)); done.Wait(); mState.store(State::LOADED); return C2_OK; @@ -910,8 +983,9 @@ void C2VDAComponent::providePictureBuffers(uint32_t minNumBuffers, const media:: // Set mRequestedVisibleRect to default. mRequestedVisibleRect = media::Rect(); - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onOutputFormatChanged, - base::Unretained(this), base::Passed(&format))); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputFormatChanged, + ::base::Unretained(this), + ::base::Passed(&format))); } void C2VDAComponent::dismissPictureBuffer(int32_t pictureBufferId) { @@ -926,28 +1000,28 @@ void C2VDAComponent::pictureReady(int32_t pictureBufferId, int32_t bitstreamId, if (mRequestedVisibleRect != cropRect) { mRequestedVisibleRect = cropRect; - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onVisibleRectChanged, - base::Unretained(this), cropRect)); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onVisibleRectChanged, + ::base::Unretained(this), cropRect)); } - mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onOutputBufferDone, base::Unretained(this), - pictureBufferId, bitstreamId)); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferDone, + ::base::Unretained(this), + pictureBufferId, bitstreamId)); } void C2VDAComponent::notifyEndOfBitstreamBuffer(int32_t bitstreamId) { - mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onInputBufferDone, - base::Unretained(this), bitstreamId)); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onInputBufferDone, + ::base::Unretained(this), bitstreamId)); } void C2VDAComponent::notifyFlushDone() { mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onDrainDone, base::Unretained(this))); + ::base::Bind(&C2VDAComponent::onDrainDone, ::base::Unretained(this))); } void C2VDAComponent::notifyResetDone() { mTaskRunner->PostTask(FROM_HERE, - base::Bind(&C2VDAComponent::onResetDone, base::Unretained(this))); + ::base::Bind(&C2VDAComponent::onResetDone, ::base::Unretained(this))); } void C2VDAComponent::notifyError(VideoDecodeAcceleratorAdaptor::Result error) { @@ -1003,16 +1077,17 @@ void C2VDAComponent::reportFinishedWorkIfAny() { } bool C2VDAComponent::isWorkDone(const C2Work* work) const { + if (work->input.buffers.empty()) { + // This is EOS work with no input buffer and should be processed by reportEOSWork(). + return false; + } if (work->input.buffers.front()) { // Input buffer is still owned by VDA. - // This condition could also recognize dummy EOS work since it won't get - // onInputBufferDone(), input buffer won't be reset until reportEOSWork(). return false; } - if (mComponentState == ComponentState::DRAINING && mDrainWithEOS && - mPendingWorks.size() == 1u) { - // If component is in DRAINING state and mDrainWithEOS is true. The last returned work - // should be marked EOS flag and returned by reportEOSWork() instead. + if (mPendingOutputEOS && mPendingWorks.size() == 1u) { + // If mPendingOutputEOS is true, the last returned work should be marked EOS flag and + // returned by reportEOSWork() instead. return false; } if (mLastOutputTimestamp < 0) { @@ -1034,9 +1109,13 @@ void C2VDAComponent::reportEOSWork() { return; } + mPendingOutputEOS = false; + std::unique_ptr<C2Work> eosWork(std::move(mPendingWorks.front())); mPendingWorks.pop_front(); - eosWork->input.buffers.front().reset(); + if (!eosWork->input.buffers.empty()) { + eosWork->input.buffers.front().reset(); + } eosWork->result = C2_OK; eosWork->workletsProcessed = static_cast<uint32_t>(eosWork->worklets.size()); eosWork->worklets.front()->output.flags = C2FrameData::FLAG_END_OF_STREAM; @@ -1056,10 +1135,26 @@ void C2VDAComponent::reportAbandonedWorks() { // TODO: correlate the definition of flushed work result to framework. work->result = C2_NOT_FOUND; - // When the work is abandoned, the input.buffers.front() shall reset by component. - work->input.buffers.front().reset(); + // When the work is abandoned, buffer in input.buffers shall reset by component. + if (!work->input.buffers.empty()) { + work->input.buffers.front().reset(); + } + abandonedWorks.emplace_back(std::move(work)); + } + + for (auto& work : mAbandonedWorks) { + // TODO: correlate the definition of flushed work result to framework. + work->result = C2_NOT_FOUND; + // When the work is abandoned, buffer in input.buffers shall reset by component. + if (!work->input.buffers.empty()) { + work->input.buffers.front().reset(); + } abandonedWorks.emplace_back(std::move(work)); } + mAbandonedWorks.clear(); + + // Pending EOS work will be abandoned here due to component flush if any. + mPendingOutputEOS = false; if (!abandonedWorks.empty()) { mListener->onWorkDone_nb(shared_from_this(), std::move(abandonedWorks)); @@ -1070,6 +1165,58 @@ void C2VDAComponent::reportError(c2_status_t error) { mListener->onError_nb(shared_from_this(), static_cast<uint32_t>(error)); } +bool C2VDAComponent::startDequeueThread(const media::Size& size, uint32_t pixelFormat, + std::shared_ptr<C2BlockPool> blockPool) { + CHECK(!mDequeueThread.IsRunning()); + if (!mDequeueThread.Start()) { + ALOGE("failed to start dequeue thread!!"); + return false; + } + mDequeueLoopStop.store(false); + mBuffersInClient.store(0u); + mDequeueThread.task_runner()->PostTask( + FROM_HERE, ::base::Bind(&C2VDAComponent::dequeueThreadLoop, ::base::Unretained(this), + size, pixelFormat, std::move(blockPool))); + return true; +} + +void C2VDAComponent::stopDequeueThread() { + if (mDequeueThread.IsRunning()) { + mDequeueLoopStop.store(true); + mDequeueThread.Stop(); + } +} + +void C2VDAComponent::dequeueThreadLoop(const media::Size& size, uint32_t pixelFormat, + std::shared_ptr<C2BlockPool> blockPool) { + ALOGV("dequeueThreadLoop starts"); + DCHECK(mDequeueThread.task_runner()->BelongsToCurrentThread()); + + while (!mDequeueLoopStop.load()) { + if (mBuffersInClient.load() == 0) { + ::usleep(kDequeueRetryDelayUs); // wait for retry + continue; + } + std::shared_ptr<C2GraphicBlock> block; + C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, 0}; + auto err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, + &block); + if (err == C2_TIMED_OUT) { + continue; // wait for retry + } + if (err == C2_OK) { + auto slot = getSlotFromGraphicBlockHandle(block->handle()); + mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferReturned, + ::base::Unretained(this), slot)); + mBuffersInClient--; + } else { + ALOGE("dequeueThreadLoop got error: %d", err); + break; + } + } + ALOGV("dequeueThreadLoop terminates"); +} + class C2VDAComponentFactory : public C2ComponentFactory { public: C2VDAComponentFactory(C2String decoderName) diff --git a/include/C2ArcVideoAcceleratorFactory.h b/include/C2ArcVideoAcceleratorFactory.h deleted file mode 100644 index 9cdaf37..0000000 --- a/include/C2ArcVideoAcceleratorFactory.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ANDROID_C2_ARC_VIDEO_ACCELERATOR_FACTORY_H -#define ANDROID_C2_ARC_VIDEO_ACCELERATOR_FACTORY_H - -#include <media/arcvideobridge/IArcVideoBridge.h> -#include <utils/Singleton.h> - -#include <components/arc/common/video.mojom.h> -#include <components/arc/common/video_decode_accelerator.mojom.h> -#include <components/arc/common/video_encode_accelerator.mojom.h> - -namespace android { -// Helper class to create message pipe to the ArcVideoAccelerator. -// This class should only be used in the Mojo thread. -class C2ArcVideoAcceleratorFactory : public Singleton<C2ArcVideoAcceleratorFactory> { -public: - bool createVideoDecodeAccelerator(::arc::mojom::VideoDecodeAcceleratorRequest request); - bool createVideoEncodeAccelerator(::arc::mojom::VideoEncodeAcceleratorRequest request); - bool createVideoProtectedBufferAllocator( - ::arc::mojom::VideoProtectedBufferAllocatorRequest request); - int32_t hostVersion() const; - -private: - C2ArcVideoAcceleratorFactory(); - - uint32_t mHostVersion; - sp<IArcVideoBridge> mArcVideoBridge; - ::arc::mojom::VideoAcceleratorFactoryPtr mRemoteFactory; - - friend class Singleton<C2ArcVideoAcceleratorFactory>; -}; -} // namespace android - -#endif // ANDROID_C2_ARC_VIDEO_ACCELERATOR_FACTORY_H diff --git a/include/C2VDAComponent.h b/include/C2VDAComponent.h index 6df3fe7..fcca0c9 100644 --- a/include/C2VDAComponent.h +++ b/include/C2VDAComponent.h @@ -132,10 +132,6 @@ private: ERROR, }; - enum { - kDpbOutputBufferExtraCount = 3, // Use the same number as ACodec. - }; - // This constant is used to tell apart from drain_mode_t enumerations in C2Component.h, which // means no drain request. // Note: this value must be different than all enumerations in drain_mode_t. @@ -156,13 +152,14 @@ private: }; int32_t mBlockId = -1; + uint32_t mSlotId = 0; State mState = State::OWNED_BY_COMPONENT; // Graphic block buffer allocated from allocator. This should be reused. std::shared_ptr<C2GraphicBlock> mGraphicBlock; // HAL pixel format used while importing to VDA. HalPixelFormat mPixelFormat; // The handle dupped from graphic block for importing to VDA. - base::ScopedFD mHandle; + ::base::ScopedFD mHandle; // VideoFramePlane information for importing to VDA. std::vector<VideoFramePlane> mPlanes; }; @@ -178,12 +175,9 @@ private: media::Rect visibleRect); }; - // Used as the release callback for C2VDAGraphicBuffer to get back the output buffer. - void returnOutputBuffer(int32_t pictureBufferId); - // These tasks should be run on the component thread |mThread|. void onDestroy(); - void onStart(media::VideoCodecProfile profile, base::WaitableEvent* done); + void onStart(media::VideoCodecProfile profile, ::base::WaitableEvent* done); void onQueueWork(std::unique_ptr<C2Work> work); void onDequeueWork(); void onInputBufferDone(int32_t bitstreamId); @@ -191,13 +185,13 @@ private: void onDrain(uint32_t drainMode); void onDrainDone(); void onFlush(); - void onStop(base::WaitableEvent* done); + void onStop(::base::WaitableEvent* done); void onResetDone(); void onFlushDone(); void onStopDone(); void onOutputFormatChanged(std::unique_ptr<VideoFormat> format); void onVisibleRectChanged(const media::Rect& cropRect); - void onOutputBufferReturned(int32_t pictureBufferId); + void onOutputBufferReturned(uint32_t slotId); // Send input buffer to accelerator with specified bitstream id. void sendInputBufferToAccelerator(const C2ConstLinearBlock& input, int32_t bitstreamId); @@ -207,6 +201,8 @@ private: void setOutputFormatCrop(const media::Rect& cropRect); // Helper function to get the specified GraphicBlockInfo object by its id. GraphicBlockInfo* getGraphicBlockById(int32_t blockId); + // Helper function to get the specified GraphicBlockInfo object by its slot index. + GraphicBlockInfo* getGraphicBlockBySlot(uint32_t slotId); // Helper function to get the specified work in mPendingWorks by bitstream id. C2Work* getPendingWorkByBitstreamId(int32_t bitstreamId); // Try to apply the output format change. @@ -220,13 +216,22 @@ private: void reportFinishedWorkIfAny(); // Make onWorkDone call to listener for reporting EOS work in mPendingWorks. void reportEOSWork(); - // Abandon all works in mPendingWorks. + // Abandon all works in mPendingWorks and mAbandonedWorks. void reportAbandonedWorks(); // Make onError call to listener for reporting errors. void reportError(c2_status_t error); // Helper function to determine if the work is finished. bool isWorkDone(const C2Work* work) const; + // Start dequeue thread, return true on success. + bool startDequeueThread(const media::Size& size, uint32_t pixelFormat, + std::shared_ptr<C2BlockPool> blockPool); + // Stop dequeue thread. + void stopDequeueThread(); + // The rountine task running on dequeue thread. + void dequeueThreadLoop(const media::Size& size, uint32_t pixelFormat, + std::shared_ptr<C2BlockPool> blockPool); + // The pointer of component interface implementation. std::shared_ptr<IntfImpl> mIntfImpl; // The pointer of component interface. @@ -235,9 +240,16 @@ private: std::shared_ptr<Listener> mListener; // The main component thread. - base::Thread mThread; + ::base::Thread mThread; // The task runner on component thread. - scoped_refptr<base::SingleThreadTaskRunner> mTaskRunner; + scoped_refptr<::base::SingleThreadTaskRunner> mTaskRunner; + + // The dequeue buffer loop thread. + ::base::Thread mDequeueThread; + // The stop signal for dequeue loop which should be atomic (toggled by main thread). + std::atomic<bool> mDequeueLoopStop; + // The count of buffers owned by client which should be atomic. + std::atomic<uint32_t> mBuffersInClient; // The following members should be utilized on component thread |mThread|. @@ -247,12 +259,13 @@ private: std::unique_ptr<VideoDecodeAcceleratorAdaptor> mVDAAdaptor; // The done event pointer of stop procedure. It should be restored in onStop() and signaled in // onStopDone(). - base::WaitableEvent* mStopDoneEvent; + ::base::WaitableEvent* mStopDoneEvent; // The state machine on component thread. ComponentState mComponentState; - // The indicator of drain mode (true for draining with EOS). This should be always set along - // with component going to DRAINING state, and only regarded under DRAINING state. - bool mDrainWithEOS; + // The indicator of draining with EOS. This should be always set along with component going to + // DRAINING state, and will be unset either after reportEOSWork() (EOS is outputted), or + // reportAbandonedWorks() (drain is cancelled and works are abandoned). + bool mPendingOutputEOS; // The vector of storing allocated output graphic block information. std::vector<GraphicBlockInfo> mGraphicBlocks; // The work queue. Works are queued along with drain mode from component API queue_nb and @@ -261,6 +274,9 @@ private: // Store all pending works. The dequeued works are placed here until they are finished and then // sent out by onWorkDone call to listener. std::deque<std::unique_ptr<C2Work>> mPendingWorks; + // Store all abandoned works. When component gets flushed/stopped, remaining works in queue are + // dumped here and sent out by onWorkDone call to listener after flush/stop is finished. + std::vector<std::unique_ptr<C2Work>> mAbandonedWorks; // Store the visible rect provided from VDA. If this is changed, component should issue a // visible size change event. media::Rect mRequestedVisibleRect; @@ -272,8 +288,13 @@ private: // Record the timestamp of the last output buffer. This is used to determine if the work is // finished. 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. @@ -285,7 +306,7 @@ private: std::mutex mStartStopLock; // The WeakPtrFactory for getting weak pointer of this. - base::WeakPtrFactory<C2VDAComponent> mWeakThisFactory; + ::base::WeakPtrFactory<C2VDAComponent> mWeakThisFactory; DISALLOW_COPY_AND_ASSIGN(C2VDAComponent); }; diff --git a/tests/Android.mk b/tests/Android.mk index 4bafb4a..3b384b4 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -21,6 +21,7 @@ LOCAL_SHARED_LIBRARIES := \ libv4l2_codec2_vda \ LOCAL_C_INCLUDES += \ + $(TOP)/device/google/cheets2/codec2/vdastore/include \ $(TOP)/external/v4l2_codec2/include \ $(TOP)/external/v4l2_codec2/vda \ $(TOP)/hardware/google/av/codec2/include \ diff --git a/tests/C2VDACompIntf_test.cpp b/tests/C2VDACompIntf_test.cpp index 6ed0753..f08ee50 100644 --- a/tests/C2VDACompIntf_test.cpp +++ b/tests/C2VDACompIntf_test.cpp @@ -5,6 +5,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "C2VDACompIntf_test" +#include <C2VDAAllocatorStore.h> #include <C2VDAComponent.h> #include <C2PlatformSupport.h> @@ -30,7 +31,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[] = {C2VDAAllocatorStore::V4L2_BUFFERQUEUE}; const C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_GRAPHIC; class C2VDACompIntfTest : public ::testing::Test { |