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

Commit 3af8a321 authored by Lajos Molnar's avatar Lajos Molnar Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'codec-surface' into mnc-dev

* changes:
  stagefright: enable experiments
  stagefright: allow connecting to surfaces that attach buffers
parents 635bc8f9 011778fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -216,6 +216,7 @@ private:
    int32_t mChannelMask;
    unsigned mDequeueCounter;
    bool mStoreMetaDataInOutputBuffers;
    bool mLegacyAdaptiveExperiment;
    int32_t mMetaDataBuffersToSubmit;
    size_t mNumUndequeuedBuffers;

+20 −0
Original line number Diff line number Diff line
@@ -108,6 +108,26 @@ struct ADebug {
    // remove redundant segments of a codec name, and return a newly allocated
    // string suitable for debugging
    static char *GetDebugName(const char *name);

    inline static bool isExperimentEnabled(
            const char *name __unused /* nonnull */, bool allow __unused = true) {
#ifdef ENABLE_STAGEFRIGHT_EXPERIMENTS
        if (!strcmp(name, "legacy-adaptive")) {
            return getExperimentFlag(allow, name, 2, 1); // every other day
        } else if (!strcmp(name, "legacy-setsurface")) {
            return getExperimentFlag(allow, name, 3, 1); // every third day
        } else {
            ALOGE("unknown experiment '%s' (disabled)", name);
        }
#endif
        return false;
    }

private:
    // pass in allow, so we can print in the log if the experiment is disabled
    static bool getExperimentFlag(
            bool allow, const char *name, uint64_t modulo, uint64_t limit,
            uint64_t plus = 0, uint64_t timeDivisor = 24 * 60 * 60 /* 1 day */);
};

}  // namespace android
+97 −17
Original line number Diff line number Diff line
@@ -422,6 +422,7 @@ ACodec::ACodec()
      mChannelMask(0),
      mDequeueCounter(0),
      mStoreMetaDataInOutputBuffers(false),
      mLegacyAdaptiveExperiment(false),
      mMetaDataBuffersToSubmit(0),
      mRepeatFrameDelayUs(-1ll),
      mMaxPtsGapUs(-1ll),
@@ -610,12 +611,16 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) {
        return err;
    }

    // need to enable allocation when attaching
    surface->getIGraphicBufferProducer()->allowAllocation(true);

    // for meta data mode, we move dequeud buffers to the new surface.
    // for non-meta mode, we must move all registered buffers
    for (size_t i = 0; i < buffers.size(); ++i) {
        const BufferInfo &info = buffers[i];
        // skip undequeued buffers for meta data mode
        if (mStoreMetaDataInOutputBuffers
                && !mLegacyAdaptiveExperiment
                && info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
            ALOGV("skipping buffer %p", info.mGraphicBuffer->getNativeBuffer());
            continue;
@@ -632,7 +637,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) {
    }

    // cancel undequeued buffers to new surface
    if (!mStoreMetaDataInOutputBuffers) {
    if (!mStoreMetaDataInOutputBuffers || mLegacyAdaptiveExperiment) {
        for (size_t i = 0; i < buffers.size(); ++i) {
            const BufferInfo &info = buffers[i];
            if (info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
@@ -967,6 +972,44 @@ status_t ACodec::allocateOutputMetaDataBuffers() {
        return err;
    mNumUndequeuedBuffers = minUndequeuedBuffers;

    if (mLegacyAdaptiveExperiment) {
        // preallocate buffers
        static_cast<Surface *>(mNativeWindow.get())
                ->getIGraphicBufferProducer()->allowAllocation(true);

        ALOGV("[%s] Allocating %u buffers from a native window of size %u on "
             "output port",
             mComponentName.c_str(), bufferCount, bufferSize);

        // Dequeue buffers then cancel them all
        for (OMX_U32 i = 0; i < bufferCount; i++) {
            ANativeWindowBuffer *buf;
            err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
            if (err != 0) {
                ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
                break;
            }

            sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
            BufferInfo info;
            info.mStatus = BufferInfo::OWNED_BY_US;
            info.mGraphicBuffer = graphicBuffer;
            mBuffers[kPortIndexOutput].push(info);
        }

        for (OMX_U32 i = 0; i < mBuffers[kPortIndexOutput].size(); i++) {
            BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
            status_t error = cancelBufferToNativeWindow(info);
            if (err == OK) {
                err = error;
            }
        }

        mBuffers[kPortIndexOutput].clear();
        static_cast<Surface*>(mNativeWindow.get())
                ->getIGraphicBufferProducer()->allowAllocation(false);
    }

    ALOGV("[%s] Allocating %u meta buffers on output port",
         mComponentName.c_str(), bufferCount);

@@ -1046,26 +1089,57 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
        return NULL;
    }

    do {
        if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) {
            ALOGE("dequeueBuffer failed.");
            return NULL;
        }

    BufferInfo *oldest = NULL;
        bool stale = false;
        for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
        BufferInfo *info =
            &mBuffers[kPortIndexOutput].editItemAt(i);
            BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);

            if (info->mGraphicBuffer != NULL &&
                info->mGraphicBuffer->handle == buf->handle) {
            CHECK_EQ((int)info->mStatus,
                     (int)BufferInfo::OWNED_BY_NATIVE_WINDOW);

                // Since consumers can attach buffers to BufferQueues, it is possible
                // that a known yet stale buffer can return from a surface that we
                // once used.  We can simply ignore this as we have already dequeued
                // this buffer properly.  NOTE: this does not eliminate all cases,
                // e.g. it is possible that we have queued the valid buffer to the
                // NW, and a stale copy of the same buffer gets dequeued - which will
                // be treated as the valid buffer by ACodec.
                if (info->mStatus != BufferInfo::OWNED_BY_NATIVE_WINDOW) {
                    ALOGI("dequeued stale buffer %p. discarding", buf);
                    stale = true;
                    break;
                }
                ALOGV("dequeued buffer %p", info->mGraphicBuffer->getNativeBuffer());
                info->mStatus = BufferInfo::OWNED_BY_US;

                return info;
            }
        }

        // It is also possible to receive a previously unregistered buffer
        // in non-meta mode. These should be treated as stale buffers. The
        // same is possible in meta mode, in which case, it will be treated
        // as a normal buffer, which is not desirable.
        // TODO: fix this.
        if (!stale && (!mStoreMetaDataInOutputBuffers || mLegacyAdaptiveExperiment)) {
            ALOGI("dequeued unrecognized (stale) buffer %p. discarding", buf);
            stale = true;
        }
        if (stale) {
            // TODO: detach stale buffer, but there is no API yet to do it.
            buf = NULL;
        }
    } while (buf == NULL);

    // get oldest undequeued buffer
    BufferInfo *oldest = NULL;
    for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
        BufferInfo *info =
            &mBuffers[kPortIndexOutput].editItemAt(i);
        if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW &&
            (oldest == NULL ||
             // avoid potential issues from counter rolling over
@@ -1384,6 +1458,7 @@ status_t ACodec::configureCodec(
    bool haveNativeWindow = msg->findObject("native-window", &obj)
            && obj != NULL && video && !encoder;
    mStoreMetaDataInOutputBuffers = false;
    mLegacyAdaptiveExperiment = false;
    if (video && !encoder) {
        inputFormat->setInt32("adaptive-playback", false);

@@ -1521,6 +1596,9 @@ status_t ACodec::configureCodec(
                ALOGV("[%s] storeMetaDataInBuffers succeeded",
                        mComponentName.c_str());
                mStoreMetaDataInOutputBuffers = true;
                mLegacyAdaptiveExperiment = ADebug::isExperimentEnabled(
                        "legacy-adaptive", !msg->contains("no-experiments"));

                inputFormat->setInt32("adaptive-playback", true);
            }

@@ -4135,7 +4213,9 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
            sp<RefBase> obj;
            CHECK(msg->findObject("surface", &obj));

            status_t err = mCodec->handleSetSurface(static_cast<Surface *>(obj.get()));
            status_t err =
                ADebug::isExperimentEnabled("legacy-setsurface") ? BAD_VALUE :
                        mCodec->handleSetSurface(static_cast<Surface *>(obj.get()));

            sp<AMessage> response = new AMessage;
            response->setInt32("err", err);
+1 −1
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ LOCAL_SHARED_LIBRARIES += \
        libdl \
        libRScpp \

LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall -DENABLE_STAGEFRIGHT_EXPERIMENTS
LOCAL_CLANG := true

LOCAL_MODULE:= libstagefright
+39 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <ctype.h>

#define LOG_TAG "ADebug"
#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/misc.h>

@@ -113,5 +114,43 @@ char *ADebug::GetDebugName(const char *name) {
    return debugName;
}

//static
bool ADebug::getExperimentFlag(
        bool allow, const char *name, uint64_t modulo,
        uint64_t limit, uint64_t plus, uint64_t timeDivisor) {
    static volatile int32_t haveSerial = 0;
    static uint64_t serialNum;
    if (!android_atomic_acquire_load(&haveSerial)) {
        // calculate initial counter value based on serial number
        static char serial[PROPERTY_VALUE_MAX];
        property_get("ro.serialno", serial, "0");
        uint64_t num = 0; // it is okay for this number to overflow
        for (size_t i = 0; i < NELEM(serial) && serial[i] != '\0'; ++i) {
            const char &c = serial[i];
            // try to use most letters of serialno
            if (isdigit(c)) {
                num = num * 10 + (c - '0');
            } else if (islower(c)) {
                num = num * 26 + (c - 'a');
            } else if (isupper(c)) {
                num = num * 26 + (c - 'A');
            } else {
                num = num * 256 + c;
            }
        }
        ALOGI("got serial");
        serialNum = num;
        android_atomic_release_store(1, &haveSerial);
    }
    ALOGI("serial: %llu, time: %llu", (long long)serialNum, (long long)time(NULL));
    // MINOR: use modulo for counter and time, so that their sum does not
    // roll over, and mess up the correlation between related experiments.
    // e.g. keep (a mod 2N) = 0 impl (a mod N) = 0
    time_t counter = (time(NULL) / timeDivisor) % modulo + plus + serialNum % modulo;
    bool enable = allow && (counter % modulo < limit);
    ALOGI("experiment '%s': %s", name, enable ? "ENABLED" : "disabled");
    return enable;
}

}  // namespace android