codec2: component start/stop implementation
This CL only cover component start and stop function without buffer allocation
and any decoding procedure.
Bug: 63828275
Test: run native tests (on nyc branch, cheets_arm device). Steps:
1) mmm external/v4l2_codec2/tests/
2) adb push out/target/product/cheets_arm/data/nativetest/C2VDAComponent_test /data/local/tmp/
3) adb shell /data/local/tmp/C2VDAComponent_test/C2VDAComponent_test
Change-Id: I96d9f4b2d6f9bd6bb28be93be3b7b5bea62e9ea7
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp
index 7c0ba9d..f9c4be9 100644
--- a/C2VDAComponent.cpp
+++ b/C2VDAComponent.cpp
@@ -9,7 +9,8 @@
#include "C2VDAAdaptor.h"
#include "C2VDAComponent.h"
-#include "video_codecs.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "videodev2.h"
#include <media/stagefright/MediaDefs.h>
@@ -428,10 +429,83 @@
node_id id,
const std::shared_ptr<C2ComponentListener>& listener)
: mIntf(std::make_shared<C2VDAComponentIntf>(name, id)),
- mListener(listener) {
+ mListener(listener),
+ mThread("C2VDAComponentThread"),
+ mVDAInitResult(VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE),
+ mComponentState(ComponentState::UNINITIALIZED),
+ mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN),
+ mState(State::UNLOADED) {
+ if (!mThread.Start()) {
+ ALOGE("Component thread failed to start");
+ return;
+ }
+ mTaskRunner = mThread.task_runner();
+ mTaskRunner->PostTask(FROM_HERE, base::Bind(&C2VDAComponent::onCreate, base::Unretained(this)));
+ mState = State::LOADED;
}
C2VDAComponent::~C2VDAComponent() {
+ CHECK_EQ(mState, State::LOADED);
+
+ if (mThread.IsRunning()) {
+ mTaskRunner->PostTask(
+ FROM_HERE, base::Bind(&C2VDAComponent::onDestroy, base::Unretained(this)));
+ mThread.Stop();
+ }
+ CHECK(!mThread.IsRunning());
+}
+
+void C2VDAComponent::getParameters() {
+ C2StreamFormatConfig::input codecProfile;
+ std::vector<C2Param* const> stackParams{ &codecProfile };
+ CHECK_EQ(mIntf->query_nb(stackParams, {}, nullptr), C2_OK);
+ // The value should be guaranteed to be within media::VideoCodecProfile enum range by component
+ // interface.
+ mCodecProfile = static_cast<media::VideoCodecProfile>(codecProfile.mValue);
+ ALOGI("get parameter: mCodecProfile = %d", static_cast<int>(mCodecProfile));
+}
+
+void C2VDAComponent::onCreate() {
+ DCHECK(mTaskRunner->BelongsToCurrentThread());
+ ALOGV("onCreate");
+ mVDAAdaptor.reset(new C2VDAAdaptor());
+}
+
+void C2VDAComponent::onDestroy() {
+ DCHECK(mTaskRunner->BelongsToCurrentThread());
+ ALOGV("onDestroy");
+ mVDAAdaptor.reset(nullptr);
+}
+
+void C2VDAComponent::onStart(media::VideoCodecProfile profile, base::WaitableEvent* done) {
+ DCHECK(mTaskRunner->BelongsToCurrentThread());
+ ALOGV("onStart");
+ CHECK(mComponentState == ComponentState::UNINITIALIZED);
+ mVDAInitResult = mVDAAdaptor->initialize(profile, this);
+ if (mVDAInitResult == VideoDecodeAcceleratorAdaptor::Result::SUCCESS) {
+ mComponentState = ComponentState::STARTED;
+ }
+ done->Signal();
+}
+
+void C2VDAComponent::onStop(base::WaitableEvent* done) {
+ DCHECK(mTaskRunner->BelongsToCurrentThread());
+ ALOGV("onStop");
+ CHECK(mComponentState != ComponentState::UNINITIALIZED);
+ mVDAAdaptor->reset();
+ mStopDoneEvent = done; // restore done event which shoud be signaled in onStopDone().
+ mComponentState = ComponentState::STOPPING;
+}
+
+void C2VDAComponent::onStopDone() {
+ DCHECK(mTaskRunner->BelongsToCurrentThread());
+ ALOGV("onStopDone");
+ CHECK(mComponentState == ComponentState::STOPPING);
+ CHECK(mStopDoneEvent);
+ mVDAAdaptor->destroy();
+ mStopDoneEvent->Signal();
+ mStopDoneEvent = nullptr;
+ mComponentState = ComponentState::UNINITIALIZED;
}
status_t C2VDAComponent::queue_nb(std::list<std::unique_ptr<C2Work>>* const items) {
@@ -459,17 +533,46 @@
}
status_t C2VDAComponent::start() {
- return C2_NOT_IMPLEMENTED;
+ if (mState != State::LOADED) {
+ return C2_BAD_STATE; // start() is only supported when component is in LOADED state.
+ }
+
+ getParameters();
+ 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));
+ return C2_CORRUPTED;
+ }
+ mState = State::RUNNING;
+ return C2_OK;
}
status_t C2VDAComponent::stop() {
- return C2_NOT_IMPLEMENTED;
+ if (!(mState == State::RUNNING || mState == State::ERROR)) {
+ return C2_BAD_STATE; // component is already in stopped state.
+ }
+
+ base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ mTaskRunner->PostTask(FROM_HERE,
+ base::Bind(&C2VDAComponent::onStop, base::Unretained(this), &done));
+ done.Wait();
+ mState = State::LOADED;
+ return C2_OK;
}
void C2VDAComponent::reset() {
+ stop();
+ // TODO(johnylin): what is the use case for calling reset() instead of stop()?
}
void C2VDAComponent::release() {
+ // TODO(johnylin): what should we do for release?
}
std::shared_ptr<C2ComponentInterface> C2VDAComponent::intf() {
@@ -483,25 +586,27 @@
UNUSED(codedSize);
}
-void C2VDAComponent::dismissPictureBuffer(int32_t picture_id) {
- UNUSED(picture_id);
+void C2VDAComponent::dismissPictureBuffer(int32_t pictureBufferId) {
+ UNUSED(pictureBufferId);
}
void C2VDAComponent::pictureReady(
- int32_t picture_id, int32_t bitstream_id, const media::Rect& cropRect) {
- UNUSED(picture_id);
- UNUSED(bitstream_id);
+ int32_t pictureBufferId, int32_t bitstreamId, const media::Rect& cropRect) {
+ UNUSED(pictureBufferId);
+ UNUSED(bitstreamId);
UNUSED(cropRect);
}
-void C2VDAComponent::notifyEndOfBitstreamBuffer(int32_t bitstream_id) {
- UNUSED(bitstream_id);
+void C2VDAComponent::notifyEndOfBitstreamBuffer(int32_t bitstreamId) {
+ UNUSED(bitstreamId);
}
void C2VDAComponent::notifyFlushDone() {
}
void C2VDAComponent::notifyResetDone() {
+ mTaskRunner->PostTask(FROM_HERE,
+ base::Bind(&C2VDAComponent::onStopDone, base::Unretained(this)));
}
void C2VDAComponent::notifyError(VideoDecodeAcceleratorAdaptor::Result error) {