Discard decode only output buffer
Workaround: if vendors do not discard the decode only
buffers, MediaCodec should not return them to clients.
Bug: 234708299
Test: atest DecodeOnlyTest
Change-Id: I1c4d7d769390f422ca4f7c8e43dc6da01e6a63e1
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 3c6c371..82249fc 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1509,6 +1509,21 @@
}
}
+bool MediaCodec::discardDecodeOnlyOutputBuffer(size_t index) {
+ Mutex::Autolock al(mBufferLock);
+ BufferInfo *info = &mPortBuffers[kPortIndexOutput][index];
+ sp<MediaCodecBuffer> buffer = info->mData;
+ int32_t flags;
+ CHECK(buffer->meta()->findInt32("flags", &flags));
+ if (flags & BUFFER_FLAG_DECODE_ONLY) {
+ info->mOwnedByClient = false;
+ info->mData.clear();
+ mBufferChannel->discardBuffer(buffer);
+ return true;
+ }
+ return false;
+}
+
// static
status_t MediaCodec::PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response) {
@@ -3198,7 +3213,8 @@
return true;
}
-bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
+MediaCodec::DequeueOutputResult MediaCodec::handleDequeueOutputBuffer(
+ const sp<AReplyToken> &replyID, bool newRequest) {
if (!isExecuting() || (mFlags & kFlagIsAsync)
|| (newRequest && (mFlags & kFlagDequeueOutputPending))) {
PostReplyWithError(replyID, INVALID_OPERATION);
@@ -3211,7 +3227,7 @@
sp<AMessage> response = new AMessage;
BufferInfo *info = peekNextPortBuffer(kPortIndexOutput);
if (!info) {
- return false;
+ return DequeueOutputResult::kNoBuffer;
}
// In synchronous mode, output format change should be handled
@@ -3222,10 +3238,13 @@
if (mFlags & kFlagOutputFormatChanged) {
PostReplyWithError(replyID, INFO_FORMAT_CHANGED);
mFlags &= ~kFlagOutputFormatChanged;
- return true;
+ return DequeueOutputResult::kRepliedWithError;
}
ssize_t index = dequeuePortBuffer(kPortIndexOutput);
+ if (discardDecodeOnlyOutputBuffer(index)) {
+ return DequeueOutputResult::kDiscardedBuffer;
+ }
response->setSize("index", index);
response->setSize("offset", buffer->offset());
@@ -3244,9 +3263,10 @@
statsBufferReceived(timeUs, buffer);
response->postReply(replyID);
+ return DequeueOutputResult::kSuccess;
}
- return true;
+ return DequeueOutputResult::kRepliedWithError;
}
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
@@ -3841,11 +3861,26 @@
handleOutputFormatChangeIfNeeded(buffer);
onOutputBufferAvailable();
} else if (mFlags & kFlagDequeueOutputPending) {
- CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
-
- ++mDequeueOutputTimeoutGeneration;
- mFlags &= ~kFlagDequeueOutputPending;
- mDequeueOutputReplyID = 0;
+ DequeueOutputResult dequeueResult =
+ handleDequeueOutputBuffer(mDequeueOutputReplyID);
+ switch (dequeueResult) {
+ case DequeueOutputResult::kNoBuffer:
+ TRESPASS();
+ break;
+ case DequeueOutputResult::kDiscardedBuffer:
+ break;
+ case DequeueOutputResult::kRepliedWithError:
+ [[fallthrough]];
+ case DequeueOutputResult::kSuccess:
+ {
+ ++mDequeueOutputTimeoutGeneration;
+ mFlags &= ~kFlagDequeueOutputPending;
+ mDequeueOutputReplyID = 0;
+ break;
+ }
+ default:
+ TRESPASS();
+ }
} else {
postActivityNotificationIfPossible();
}
@@ -4544,27 +4579,39 @@
break;
}
- if (handleDequeueOutputBuffer(replyID, true /* new request */)) {
- break;
- }
+ DequeueOutputResult dequeueResult =
+ handleDequeueOutputBuffer(replyID, true /* new request */);
+ switch (dequeueResult) {
+ case DequeueOutputResult::kNoBuffer:
+ [[fallthrough]];
+ case DequeueOutputResult::kDiscardedBuffer:
+ {
+ int64_t timeoutUs;
+ CHECK(msg->findInt64("timeoutUs", &timeoutUs));
- int64_t timeoutUs;
- CHECK(msg->findInt64("timeoutUs", &timeoutUs));
+ if (timeoutUs == 0LL) {
+ PostReplyWithError(replyID, -EAGAIN);
+ break;
+ }
- if (timeoutUs == 0LL) {
- PostReplyWithError(replyID, -EAGAIN);
- break;
- }
+ mFlags |= kFlagDequeueOutputPending;
+ mDequeueOutputReplyID = replyID;
- mFlags |= kFlagDequeueOutputPending;
- mDequeueOutputReplyID = replyID;
-
- if (timeoutUs > 0LL) {
- sp<AMessage> timeoutMsg =
- new AMessage(kWhatDequeueOutputTimedOut, this);
- timeoutMsg->setInt32(
- "generation", ++mDequeueOutputTimeoutGeneration);
- timeoutMsg->post(timeoutUs);
+ if (timeoutUs > 0LL) {
+ sp<AMessage> timeoutMsg =
+ new AMessage(kWhatDequeueOutputTimedOut, this);
+ timeoutMsg->setInt32(
+ "generation", ++mDequeueOutputTimeoutGeneration);
+ timeoutMsg->post(timeoutUs);
+ }
+ break;
+ }
+ case DequeueOutputResult::kRepliedWithError:
+ [[fallthrough]];
+ case DequeueOutputResult::kSuccess:
+ break;
+ default:
+ TRESPASS();
}
break;
}
@@ -5553,6 +5600,9 @@
void MediaCodec::onOutputBufferAvailable() {
int32_t index;
while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
+ if (discardDecodeOnlyOutputBuffer(index)) {
+ continue;
+ }
const sp<MediaCodecBuffer> &buffer =
mPortBuffers[kPortIndexOutput][index].mData;
sp<AMessage> msg = mCallback->dup();
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index cba2250..dbc97db 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -410,6 +410,13 @@
kBufferRendered,
};
+ enum class DequeueOutputResult {
+ kNoBuffer,
+ kDiscardedBuffer,
+ kRepliedWithError,
+ kSuccess,
+ };
+
struct ResourceManagerServiceProxy;
State mState;
@@ -556,7 +563,9 @@
sp<MediaCodecBuffer> *buffer, sp<AMessage> *format);
bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
- bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
+ DequeueOutputResult handleDequeueOutputBuffer(
+ const sp<AReplyToken> &replyID,
+ bool newRequest = false);
void cancelPendingDequeueOperations();
void extractCSD(const sp<AMessage> &format);
@@ -640,6 +649,7 @@
void statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
void statsBufferReceived(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
+ bool discardDecodeOnlyOutputBuffer(size_t index);
enum {
// the default shape of our latency histogram buckets