Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79608158 authored by Chong Zhang's avatar Chong Zhang
Browse files

stagefright: measure max encoder buffer count for persistent surface

bug: 19127604

Change-Id: I9a9b29b527d20f43a5a0188380baf2242bd31507
parent 2232aee2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@

namespace android {

extern const char *kMaxEncoderInputBuffers;

struct AMessage;

struct MediaCodecList : public BnMediaCodecList {
+30 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <media/ICrypto.h>
#include <media/IOMX.h>
@@ -320,6 +321,27 @@ sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
    CHECK_EQ(client.connect(), (status_t)OK);
    sp<IOMX> omx = client.interface();

    const sp<IMediaCodecList> mediaCodecList = MediaCodecList::getInstance();
    if (mediaCodecList == NULL) {
        ALOGE("Failed to obtain MediaCodecList!");
        return NULL; // if called from Java should raise IOException
    }

    AString tmp;
    sp<AMessage> globalSettings = mediaCodecList->getGlobalSettings();
    if (globalSettings == NULL || !globalSettings->findString(
            kMaxEncoderInputBuffers, &tmp)) {
        ALOGE("Failed to get encoder input buffer count!");
        return NULL;
    }

    int32_t bufferCount = strtol(tmp.c_str(), NULL, 10);
    if (bufferCount <= 0
            || bufferCount > BufferQueue::MAX_MAX_ACQUIRED_BUFFERS) {
        ALOGE("Encoder input buffer count is invalid!");
        return NULL;
    }

    sp<IGraphicBufferProducer> bufferProducer;
    sp<IGraphicBufferConsumer> bufferConsumer;

@@ -331,6 +353,14 @@ sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
        return NULL;
    }

    err = bufferConsumer->setMaxAcquiredBufferCount(bufferCount);

    if (err != NO_ERROR) {
        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
                bufferCount, err);
        return NULL;
    }

    return new PersistentSurface(bufferProducer, bufferConsumer);
}

+2 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@

namespace android {

const char *kMaxEncoderInputBuffers = "max-video-encoder-input-buffers";

static Mutex sInitMutex;

static MediaCodecList *gCodecList = NULL;
+72 −4
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@
#include <media/IMediaCodecList.h>
#include <media/MediaCodecInfo.h>
#include <media/MediaResourcePolicy.h>
#include <media/openmax/OMX_IVCommon.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>

namespace android {

@@ -86,6 +88,7 @@ static sp<AMessage> getMeasureFormat(
        int32_t bitrate = 0;
        getMeasureBitrate(caps, &bitrate);
        format->setInt32("bitrate", bitrate);
        format->setInt32("encoder", 1);
    }

    if (mime.startsWith("video/")) {
@@ -114,15 +117,67 @@ static sp<AMessage> getMeasureFormat(
    return format;
}

static size_t doProfileEncoderInputBuffers(
        AString name, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
    ALOGV("doProfileEncoderInputBuffers: name %s, mime %s", name.c_str(), mime.c_str());

    sp<AMessage> format = getMeasureFormat(true /* isEncoder */, mime, caps);
    if (format == NULL) {
        return 0;
    }

    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
    ALOGV("doProfileEncoderInputBuffers: format %s", format->debugString().c_str());

    status_t err = OK;
    sp<ALooper> looper = new ALooper;
    looper->setName("MediaCodec_looper");
    looper->start(
            false /* runOnCallingThread */, false /* canCallJava */, ANDROID_PRIORITY_AUDIO);

    sp<MediaCodec> codec = MediaCodec::CreateByComponentName(looper, name.c_str(), &err);
    if (err != OK) {
        ALOGE("Failed to create codec: %s", name.c_str());
        return 0;
    }

    err = codec->configure(format, NULL, NULL, MediaCodec::CONFIGURE_FLAG_ENCODE);
    if (err != OK) {
        ALOGE("Failed to configure codec: %s with mime: %s", name.c_str(), mime.c_str());
        codec->release();
        return 0;
    }

    sp<IGraphicBufferProducer> bufferProducer;
    err = codec->createInputSurface(&bufferProducer);
    if (err != OK) {
        ALOGE("Failed to create surface: %s with mime: %s", name.c_str(), mime.c_str());
        codec->release();
        return 0;
    }

    int minUndequeued = 0;
    err = bufferProducer->query(
            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeued);
    if (err != OK) {
        ALOGE("Failed to query NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS");
        minUndequeued = 0;
    }

    err = codec->release();
    if (err != OK) {
        ALOGW("Failed to release codec: %s with mime: %s", name.c_str(), mime.c_str());
    }

    return minUndequeued;
}

static size_t doProfileCodecs(
        bool isEncoder, AString name, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
    sp<AMessage> format = getMeasureFormat(isEncoder, mime, caps);
    if (format == NULL) {
        return 0;
    }
    if (isEncoder) {
        format->setInt32("encoder", 1);
    }
    ALOGV("doProfileCodecs %s %s %s %s",
            name.c_str(), mime.c_str(), isEncoder ? "encoder" : "decoder",
            format->debugString().c_str());
@@ -144,7 +199,7 @@ static size_t doProfileCodecs(
        }
        const sp<Surface> nativeWindow;
        const sp<ICrypto> crypto;
        uint32_t flags = 0;
        uint32_t flags = isEncoder ? MediaCodec::CONFIGURE_FLAG_ENCODE : 0;
        ALOGV("doProfileCodecs configure");
        err = codec->configure(format, nativeWindow, crypto, flags);
        if (err != OK) {
@@ -211,6 +266,7 @@ void profileCodecs(
        bool forceToMeasure) {
    KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
    AString supportMultipleSecureCodecs = "true";
    size_t maxEncoderInputBuffers = 0;
    for (size_t i = 0; i < infos.size(); ++i) {
        const sp<MediaCodecInfo> info = infos[i];
        AString name = info->getCodecName();
@@ -251,8 +307,20 @@ void profileCodecs(
                        supportMultipleSecureCodecs = "false";
                    }
                }
                if (info->isEncoder() && mimes[i].startsWith("video/")) {
                    size_t encoderInputBuffers =
                        doProfileEncoderInputBuffers(name, mimes[i], caps);
                    if (encoderInputBuffers > maxEncoderInputBuffers) {
                        maxEncoderInputBuffers = encoderInputBuffers;
                    }
                }
            }
        }
    }
    if (maxEncoderInputBuffers > 0) {
        char tmp[32];
        sprintf(tmp, "%zu", maxEncoderInputBuffers);
        global_results->add(kMaxEncoderInputBuffers, tmp);
    }
    global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
}
+1 −9
Original line number Diff line number Diff line
@@ -868,17 +868,9 @@ status_t OMXNodeInstance::createPersistentInputSurface(
    consumer->setConsumerName(name);
    consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);

    status_t err = consumer->setMaxAcquiredBufferCount(
            BufferQueue::MAX_MAX_ACQUIRED_BUFFERS);
    if (err != NO_ERROR) {
        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
                BufferQueue::MAX_MAX_ACQUIRED_BUFFERS, err);
        return err;
    }

    sp<BufferQueue::ProxyConsumerListener> proxy =
        new BufferQueue::ProxyConsumerListener(NULL);
    err = consumer->consumerConnect(proxy, false);
    status_t err = consumer->consumerConnect(proxy, false);
    if (err != NO_ERROR) {
        ALOGE("Error connecting to BufferQueue: %s (%d)",
                strerror(-err), err);