Workaround impl in acodec / ccodec
Bug: 234708299
Test: atest DecodeOnlyTest
Change-Id: I293da198837e2bbbc73360e9cfa175643c497387
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6bb115a..b54d35d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1998,6 +1998,12 @@
drop = true;
}
+ // Workaround: if C2FrameData::FLAG_DROP_FRAME is not implemented in
+ // HAL, the flag is then removed in the corresponding output buffer.
+ if (work->input.flags & C2FrameData::FLAG_DROP_FRAME) {
+ flags |= BUFFER_FLAG_DECODE_ONLY;
+ }
+
if (notifyClient && !buffer && !flags) {
if (mTunneled && drop && outputFormat) {
ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 89e0015..4a5524d 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6318,6 +6318,7 @@
int32_t isDecodeOnly = 0;
if (buffer->meta()->findInt32("decode-only", &isDecodeOnly) && isDecodeOnly != 0) {
flags |= OMX_BUFFERFLAG_DECODEONLY;
+ mCodec->mDecodeOnlyTimesUs.emplace(timeUs);
}
size_t size = buffer->size();
size_t offset = buffer->offset();
@@ -6350,7 +6351,7 @@
} else {
if (flags & OMX_BUFFERFLAG_DECODEONLY) {
ALOGV("[%s] calling emptyBuffer %u w/ decode only flag",
- mCodec->mComponentName.c_str(), bufferID);
+ mCodec->mComponentName.c_str(), bufferID);
}
#if TRACK_BUFFER_TIMING
ALOGI("[%s] calling emptyBuffer %u w/ time %lld us",
@@ -6642,6 +6643,39 @@
info->mData.clear();
+ // Workaround: if OMX_BUFFERFLAG_DECODEONLY is not implemented in
+ // HAL, the flag is then removed in the corresponding output buffer.
+
+ // for all buffers that were marked as DECODE_ONLY, remove their timestamp
+ // if it is smaller than the timestamp of the buffer that was
+ // just received
+ while (!mCodec->mDecodeOnlyTimesUs.empty() &&
+ *mCodec->mDecodeOnlyTimesUs.begin() < timeUs) {
+ mCodec->mDecodeOnlyTimesUs.erase(mCodec->mDecodeOnlyTimesUs.begin());
+ }
+ // if OMX_BUFFERFLAG_DECODEONLY is not implemented in HAL, we need to restore the
+ // OMX_BUFFERFLAG_DECODEONLY flag to the frames we had saved in the set, the set
+ // contains the timestamps of buffers that were marked as DECODE_ONLY by the app
+ if (!mCodec->mDecodeOnlyTimesUs.empty() &&
+ *mCodec->mDecodeOnlyTimesUs.begin() == timeUs) {
+ mCodec->mDecodeOnlyTimesUs.erase(timeUs);
+ // If the app queued the last valid buffer as DECODE_ONLY and queued an additional
+ // empty buffer as EOS, it's possible that HAL sets the last valid frame as EOS
+ // instead and drops the empty buffer. In such a case, we should not add back
+ // the OMX_BUFFERFLAG_DECODEONLY flag to it, as doing so will make it so that the
+ // app does not receive the EOS buffer, which breaks the contract of EOS buffers
+ if (flags & OMX_BUFFERFLAG_EOS) {
+ // Set buffer size to 0, as described by
+ // https://developer.android.com/reference/android/media/MediaCodec.BufferInfo?hl=en#size
+ // a buffer of size 0 should only be used to carry the EOS flag and should
+ // be discarded by the app as it has no data
+ buffer->setRange(0, 0);
+ } else {
+ // re-add the OMX_BUFFERFLAG_DECODEONLY flag to the buffer in case it is
+ // not the end of stream buffer
+ flags |= OMX_BUFFERFLAG_DECODEONLY;
+ }
+ }
mCodec->mBufferChannel->drainThisBuffer(info->mBufferID, flags);
info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
@@ -6862,6 +6896,7 @@
mCodec->mConverter[0].clear();
mCodec->mConverter[1].clear();
mCodec->mComponentName.clear();
+ mCodec->mDecodeOnlyTimesUs.clear();
}
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
@@ -8847,6 +8882,7 @@
ALOGV("[%s] Now Flushing", mCodec->mComponentName.c_str());
mFlushComplete[kPortIndexInput] = mFlushComplete[kPortIndexOutput] = false;
+ mCodec->mDecodeOnlyTimesUs.clear();
// If we haven't transitioned after 3 seconds, we're probably stuck.
sp<AMessage> msg = new AMessage(ACodec::kWhatCheckIfStuck, mCodec);
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index fbb3788..c5a59ff 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -642,6 +642,9 @@
if (omxFlags & OMX_BUFFERFLAG_EOS) {
flags |= MediaCodec::BUFFER_FLAG_EOS;
}
+ if (omxFlags & OMX_BUFFERFLAG_DECODEONLY) {
+ flags |= MediaCodec::BUFFER_FLAG_DECODE_ONLY;
+ }
it->mClientBuffer->meta()->setInt32("flags", flags);
mCallback->onOutputBufferAvailable(
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 38a4c1e..08c7917 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -17,6 +17,7 @@
#ifndef A_CODEC_H_
#define A_CODEC_H_
+#include <set>
#include <stdint.h>
#include <list>
#include <vector>
@@ -270,6 +271,7 @@
std::vector<BufferInfo> mBuffers[2];
bool mPortEOS[2];
status_t mInputEOSResult;
+ std::set<int64_t> mDecodeOnlyTimesUs;
std::list<sp<AMessage>> mDeferredQueue;