Переключение видео SurfaceView будет мигать

описание проблемы

В последнее время использую 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 будет мигать какое-то время, я надеюсь, что некоторые великие боги дадут какие-то указатели, когда будут проходить мимо. Я также надеюсь, что друзья, столкнувшиеся с той же проблемой, смогут вместе поделиться своим опытом. Спасибо!

Guess you like

Origin blog.csdn.net/qq_35831940/article/details/126467784