Fix race b/w prepareInitialInputBuffers and feedInputBuffersIfAvailable
After flush, input buffers can be either with codec or
framework. Bufferchannel was started before prepareInitialInputBuffers,
which caused input buffer returning through onWorkDone sent to
client. The was causing a failure during prepare buffers stage.
With this change, the buferchannel is only started after the
the preparation is complete.
For the buffers not yet released by the codec after flush and before
signalResume, the failure in prepareInitialInputBuffers will be
recovered immediatly as the bufers are released. So this failure
is logged and the codec is allowed to contine without errors.
Bug: 245397641
Test: manual per b/237656746#comment19
Test: atest android.media.decoder.cts.AdaptivePlaybackTest
Test: atest android.media.cts.MediaCodecTest
Change-Id: I8051d0b2d74f251964b733a7b7948a9d626c011e
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index eb1b4b5..2db6f2f 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1828,6 +1828,7 @@
mCallback->onError(err2, ACTION_CODE_FATAL);
return;
}
+
err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec);
if (err2 != OK) {
mCallback->onError(err2, ACTION_CODE_FATAL);
@@ -2131,6 +2132,25 @@
RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
}
+ std::map<size_t, sp<MediaCodecBuffer>> clientInputBuffers;
+ status_t err = mChannel->prepareInitialInputBuffers(&clientInputBuffers);
+ if (err != OK) {
+ if (err == NO_MEMORY) {
+ // NO_MEMORY happens here when all the buffers are still
+ // with the codec. That is not an error as it is momentarily
+ // and the buffers are send to the client as soon as the codec
+ // releases them
+ ALOGI("Resuming with all input buffers still with codec");
+ } else {
+ ALOGE("Resume request for Input Buffers failed");
+ mCallback->onError(err, ACTION_CODE_FATAL);
+ return;
+ }
+ }
+
+ // channel start should be called after prepareInitialBuffers
+ // Calling before can cause a failure during prepare when
+ // buffers are sent to the client before preparation from onWorkDone
(void)mChannel->start(nullptr, nullptr, [&]{
Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
const std::unique_ptr<Config> &config = *configLocked;
@@ -2148,14 +2168,6 @@
state->set(RUNNING);
}
- std::map<size_t, sp<MediaCodecBuffer>> clientInputBuffers;
- status_t err = mChannel->prepareInitialInputBuffers(&clientInputBuffers);
- // FIXME(b/237656746)
- if (err != OK && err != NO_MEMORY) {
- ALOGE("Resume request for Input Buffers failed");
- mCallback->onError(err, ACTION_CODE_FATAL);
- return;
- }
mChannel->requestInitialInputBuffers(std::move(clientInputBuffers));
}