aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPin-chih Lin <johnylin@google.com>2018-05-30 16:48:07 +0800
committerPin-chih Lin <johnylin@google.com>2018-06-19 11:08:52 +0800
commit617d7634c57bdfd539f3bee57220bfad8c31ec44 (patch)
tree07f2de3b6a91f39ebe47578d04b089d5049470d9
parent29d50d91cc8829fa92a72276750681dcd30f38c4 (diff)
downloadv4l2_codec2-617d7634c57bdfd539f3bee57220bfad8c31ec44.tar.gz
codec2: put abandoned works to another vector apart from mPendingWorks
Flush signal would be succeeded by draining, for this case in onDrainDone() we should also expect state in FLUSHING and still wait for onFlushDone(). In order to handle reportEOSWork() by draining for this case, we should not mix up pending works (waiting for VDA processed) and abandoned works. A vector mAbandonedWorks is introduced to temporarily place abandoned works, and passed to listener for abandoning in reportAbandonedWorks() call. Bug: 80452475 Test: CtsMediaTestCases android.media.cts.MediaPlayerTest#testLocalVideo_MP4_H264_480x360_1000kbps_25fps_AAC_Stereo_128kbps_44110Hz Change-Id: I38ed72222a2276f85485e57409adc88e53fe416e
-rw-r--r--C2VDAComponent.cpp48
-rw-r--r--include/C2VDAComponent.h12
2 files changed, 40 insertions, 20 deletions
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp
index fcae9df..a6698cf 100644
--- a/C2VDAComponent.cpp
+++ b/C2VDAComponent.cpp
@@ -208,7 +208,7 @@ C2VDAComponent::C2VDAComponent(C2String name, c2_node_id_t id,
mDequeueThread("C2VDAComponentDequeueThread"),
mVDAInitResult(VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE),
mComponentState(ComponentState::UNINITIALIZED),
- mDrainWithEOS(false),
+ mPendingOutputEOS(false),
mLastOutputTimestamp(-1),
mSurfaceMode(true),
mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN),
@@ -325,7 +325,7 @@ 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.
@@ -443,7 +443,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);
}
@@ -461,13 +461,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();
}
@@ -485,15 +487,16 @@ void C2VDAComponent::onDrainDone() {
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;
@@ -510,9 +513,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();
}
@@ -1075,10 +1078,9 @@ bool C2VDAComponent::isWorkDone(const C2Work* work) const {
// 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) {
@@ -1100,6 +1102,8 @@ void C2VDAComponent::reportEOSWork() {
return;
}
+ mPendingOutputEOS = false;
+
std::unique_ptr<C2Work> eosWork(std::move(mPendingWorks.front()));
mPendingWorks.pop_front();
eosWork->input.buffers.front().reset();
@@ -1127,6 +1131,18 @@ void C2VDAComponent::reportAbandonedWorks() {
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, the input.buffers.front() shall reset by component.
+ 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));
}
diff --git a/include/C2VDAComponent.h b/include/C2VDAComponent.h
index c612567..fcca0c9 100644
--- a/include/C2VDAComponent.h
+++ b/include/C2VDAComponent.h
@@ -216,7 +216,7 @@ 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);
@@ -262,9 +262,10 @@ private:
::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
@@ -273,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;