описание проблемы
В последнее время использую MediaCodec для воспроизведения видео.При переключении программ на маленьком экране малый экран мерцает (черный экран -> прозрачный -> видеоэкран.
Увидев это явление, я подумал о решении, которое заключается в том, чтобы сослаться на обработку затемнения в LiveTv в кадре tif.Когда воспроизведение остановлено, наложить View с черным фоном на SurfaceView, а затем дождаться появится экран видео. Вид скрыт, поэтому экран-заставка исчезает.
Однако полученная мной информация о рисовании представляется неточной, а скорость отрисовки после квазимодификации кажется не такой быстрой, как раньше, поэтому я решил выяснить первопричину.
Анализ причин:
После добавления большого количества журналов отладки я наконец нашел ключ к проблеме в SurfaceUtils.cpp.
То есть, когда MediaCodec останавливается, это вызвано вызовом метода pushBlankBuffersToNativeWindow, область SurfaceView будет отображаться черным цветом, а поскольку SurfaceView будет прозрачным или полупрозрачным перед рисованием, то в итоге будет черный экран -> прозрачный -> вспышка видеоэкран Феномен.
Итак, как предотвратить остановку MediaCodec от вызова pushBlankBuffersToNativeWindow?
В ACodec.cpp после добавления анализа логов кажется неизбежным без изменения кода фреймворка.
Связанный путь кода:
android/frameworks/av/media/libstagefright/ACodec.cpp
android/frameworks/av/media/libstagefright/SurfaceUtils.cpp
Причины следующие:
MediaCodec должен рисовать, а CodeName MediaCodec должен заканчиваться на .secure, поэтому mCodec->mFlags добавит флаги kFlagPushBlankBuffersToNativeWindowOnShutdown.
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
ALOGV("onAllocateComponent");
CHECK(mCodec->mOMXNode == NULL);
mCodec->mFatalError = false;
sp<AMessage> notify = new AMessage(kWhatOMXMessageList, mCodec);
notify->setInt32("generation", mCodec->mNodeGeneration + 1);
sp<RefBase> obj;
CHECK(msg->findObject("codecInfo", &obj));
sp<MediaCodecInfo> info = (MediaCodecInfo *)obj.get();
if (info == nullptr) {
ALOGE("Unexpected nullptr for codec information");
mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
return false;
}
AString owner = (info->getOwnerName() == nullptr) ? "default" : info->getOwnerName();
AString componentName;
CHECK(msg->findString("componentName", &componentName));
sp<CodecObserver> observer = new CodecObserver(notify);
sp<IOMX> omx;
sp<IOMXNode> omxNode;
status_t err = NAME_NOT_FOUND;
OMXClient client;
if (client.connect(owner.c_str()) != OK) {
mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
return false;
}
omx = client.interface();
pid_t tid = gettid();
int prevPriority = androidGetThreadPriority(tid);
androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
androidSetThreadPriority(tid, prevPriority);
if (err != OK) {
ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);
mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
return false;
}
mDeathNotifier = new DeathNotifier(new AMessage(kWhatOMXDied, mCodec));
auto tOmxNode = omxNode->getHalInterface<IOmxNode>();
if (tOmxNode && !tOmxNode->linkToDeath(mDeathNotifier, 0)) {
mDeathNotifier.clear();
}
++mCodec->mNodeGeneration;
mCodec->mComponentName = componentName;
mCodec->mRenderTracker.setComponentName(componentName);
mCodec->mFlags = 0;
//kFlagPushBlankBuffersToNativeWindowOnShutdown 设置了遮黑的flags
if (componentName.endsWith(".secure")) {
mCodec->mFlags |= kFlagIsSecure;
mCodec->mFlags |= kFlagIsGrallocUsageProtected;
mCodec->mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
}
mCodec->mOMX = omx;
mCodec->mOMXNode = omxNode;
mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
mCodec->changeState(mCodec->mLoadedState);
return true;
}
Когда MediaCodec остановится, mCodec->mFlags будет оцениваться снова, что приведет к вызову pushBlankBuffersToNativeWindow.
void ACodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() {
if (mComponentNowIdle && mCodec->allYourBuffersAreBelongToUs()) {
status_t err = mCodec->mOMXNode->sendCommand(
OMX_CommandStateSet, OMX_StateLoaded);
if (err == OK) {
err = mCodec->freeBuffersOnPort(kPortIndexInput);
status_t err2 = mCodec->freeBuffersOnPort(kPortIndexOutput);
if (err == OK) {
err = err2;
}
}
//判断使用遮黑的flags
if ((mCodec->mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown)
&& mCodec->mNativeWindow != NULL) {
// We push enough 1x1 blank buffers to ensure that one of
// them has made it to the display. This allows the OMX
// component teardown to zero out any protected buffers
// without the risk of scanning out one of those buffers.
pushBlankBuffersToNativeWindow(mCodec->mNativeWindow.get());
}
if (err != OK) {
mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
return;
}
mCodec->changeState(mCodec->mIdleToLoadedState);
}
}
Подведем итог
Что касается проблемы, что MediaCodec будет мигать какое-то время, я надеюсь, что некоторые великие боги дадут какие-то указатели, когда будут проходить мимо. Я также надеюсь, что друзья, столкнувшиеся с той же проблемой, смогут вместе поделиться своим опытом. Спасибо!