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
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp
index fcae9df..a6698cf 100644
--- a/C2VDAComponent.cpp
+++ b/C2VDAComponent.cpp
@@ -208,7 +208,7 @@
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 @@
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 @@
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 @@
} 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::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 @@
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 @@
// 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 @@
return;
}
+ mPendingOutputEOS = false;
+
std::unique_ptr<C2Work> eosWork(std::move(mPendingWorks.front()));
mPendingWorks.pop_front();
eosWork->input.buffers.front().reset();
@@ -1127,6 +1131,18 @@
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));
}