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

Commit 47e40ae3 authored by Apurupa Pattapu's avatar Apurupa Pattapu Committed by Ricardo Cerqueira
Browse files

frameworks/base/nuplayer: Support for dynamic port reconfig in HTTP Live

- BW switch is detected by the decoder by a port reconfig event
  instead of a discontinuity event
- Handle port reconfig dyanamically in ACodec
  Steps are - Flush - Get all buffers back - Disable - Enable
- Handle PID change in TS Parser - Set PID based on stream type

Patchset 1: Add QCOM_HARDWARE ifdefs

Conflicts:

	media/libstagefright/ACodec.cpp

Change-Id: I5ff494084fffa218cafd3cd6db1197aad2233c4d
parent 7a5d4bb6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -63,6 +63,9 @@ private:
    struct ExecutingToIdleState;
    struct IdleToLoadedState;
    struct FlushingState;
#ifdef QCOM_HARDWARE
    struct FlushingOutputState;
#endif

    enum {
        kWhatSetup                   = 'setu',
@@ -106,6 +109,9 @@ private:
    sp<ExecutingToIdleState> mExecutingToIdleState;
    sp<IdleToLoadedState> mIdleToLoadedState;
    sp<FlushingState> mFlushingState;
#ifdef QCOM_HARDWARE
    sp<FlushingOutputState> mFlushingOutputState;
#endif

    AString mComponentName;
    sp<IOMX> mOMX;
+151 −3
Original line number Diff line number Diff line
@@ -360,6 +360,30 @@ private:

////////////////////////////////////////////////////////////////////////////////

#ifdef QCOM_HARDWARE
struct ACodec::FlushingOutputState : public ACodec::BaseState {
    FlushingOutputState(ACodec *codec);

protected:
    virtual bool onMessageReceived(const sp<AMessage> &msg);
    virtual void stateEntered();

    virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);

    virtual void onOutputBufferDrained(const sp<AMessage> &msg);
    virtual void onInputBufferFilled(const sp<AMessage> &msg);

private:
    bool mFlushComplete;

    void changeStateIfWeOwnAllBuffers();

    DISALLOW_EVIL_CONSTRUCTORS(FlushingOutputState);
};

////////////////////////////////////////////////////////////////////////////////
#endif

ACodec::ACodec()
    : mNode(NULL),
#ifdef QCOM_HARDWARE
@@ -379,6 +403,9 @@ ACodec::ACodec()
    mExecutingToIdleState = new ExecutingToIdleState(this);
    mIdleToLoadedState = new IdleToLoadedState(this);
    mFlushingState = new FlushingState(this);
#ifdef QCOM_HARDWARE
    mFlushingOutputState = new FlushingOutputState(this);
#endif

    mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false;
    mInputEOSResult = OK;
@@ -1245,7 +1272,7 @@ bool ACodec::allYourBuffersAreBelongToUs(

        if (info->mStatus != BufferInfo::OWNED_BY_US
                && info->mStatus != BufferInfo::OWNED_BY_NATIVE_WINDOW) {
            LOGV("[%s] Buffer %p on port %ld still has status %d",
            LOGE("[%s] Buffer %p on port %ld still has status %d",
                    mComponentName.c_str(),
                    info->mBufferID, portIndex, info->mStatus);
            return false;
@@ -2431,13 +2458,20 @@ bool ACodec::ExecutingState::onOMXEvent(
            if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
                LOGV("Flush output port before disable");
                CHECK_EQ(mCodec->mOMX->sendCommand(
#ifdef QCOM_HARDWARE
                        mCodec->mNode, OMX_CommandFlush, kPortIndexOutput),
#else
                            mCodec->mNode,
                            OMX_CommandPortDisable, kPortIndexOutput),
#endif
                     (status_t)OK);

#ifdef QCOM_HARDWARE
                mCodec->changeState(mCodec->mFlushingOutputState);
#else
                mCodec->freeOutputBuffersNotOwnedByComponent();

                mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
#endif
            } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
                mCodec->mSentFormat = false;
            } else {
@@ -2854,4 +2888,118 @@ void ACodec::FlushingState::changeStateIfWeOwnAllBuffers() {
    }
}

#ifdef QCOM_HARDWARE
////////////////////////////////////////////////////////////////////////////////

ACodec::FlushingOutputState::FlushingOutputState(ACodec *codec)
    : BaseState(codec) {
}

void ACodec::FlushingOutputState::stateEntered() {
    LOGV("[%s] Now Flushing Output Port", mCodec->mComponentName.c_str());

    mFlushComplete = false;
}

bool ACodec::FlushingOutputState::onMessageReceived(const sp<AMessage> &msg) {
    bool handled = false;

    switch (msg->what()) {
        case kWhatShutdown:
        {
            mCodec->deferMessage(msg);
            break;
        }

        case kWhatFlush:
        {
            LOGV("Flush received during port reconfig, deferring it");
            mCodec->deferMessage(msg);
            break;
        }
        default:
            handled = BaseState::onMessageReceived(msg);
            break;
    }

    return handled;
}

bool ACodec::FlushingOutputState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    switch (event) {
        case OMX_EventCmdComplete:
        {
            CHECK_EQ(data1, (OMX_U32)OMX_CommandFlush);
            CHECK_EQ(data2,(OMX_U32)kPortIndexOutput);
            LOGV("FlushingOutputState::onOMXEvent Output port flush complete");
            mFlushComplete = true;
            changeStateIfWeOwnAllBuffers();
            return true;
        }

        case OMX_EventPortSettingsChanged:
        {
            sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
            msg->setInt32("type", omx_message::EVENT);
            msg->setPointer("node", mCodec->mNode);
            msg->setInt32("event", event);
            msg->setInt32("data1", data1);
            msg->setInt32("data2", data2);

            LOGV("[%s] Deferring OMX_EventPortSettingsChanged",
                 mCodec->mComponentName.c_str());

            mCodec->deferMessage(msg);

            return true;
        }

        default:
            return BaseState::onOMXEvent(event, data1, data2);
    }

    return true;
}

void ACodec::FlushingOutputState::onOutputBufferDrained(const sp<AMessage> &msg) {
    BaseState::onOutputBufferDrained(msg);

    changeStateIfWeOwnAllBuffers();
}

void ACodec::FlushingOutputState::onInputBufferFilled(const sp<AMessage> &msg) {
    BaseState::onInputBufferFilled(msg);

    changeStateIfWeOwnAllBuffers();
}

void ACodec::FlushingOutputState::changeStateIfWeOwnAllBuffers() {
   LOGV("FlushingOutputState::ChangeState %d",mFlushComplete);
   if (mFlushComplete && mCodec->allYourBuffersAreBelongToUs( kPortIndexOutput )) {
        /*** TO DO - Enable this when display API is available ***/
        /*
        LOGV("sending native window reconfigure for after port reconfig");
        status_t err = native_window_reconfigure_buffers(mCodec->mNativeWindow.get());
        if(err != 0){
           LOGV("native_window_reconfigure_buffers call failed\n");
        }
        */
        LOGV("FlushingOutputState Sending port disable ");
        CHECK_EQ(mCodec->mOMX->sendCommand(
                            mCodec->mNode,
                            OMX_CommandPortDisable, kPortIndexOutput),
                         (status_t)OK);

        mCodec->mPortEOS[kPortIndexInput] = false;
        mCodec->mPortEOS[kPortIndexOutput] = false;

        LOGV("FlushingOutputState Calling freeOutputBuffersNotOwnedByComponent");
        mCodec->freeOutputBuffersNotOwnedByComponent();

        LOGV("FlushingOutputState Change state to port settings changed");
        mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
    }
}
#endif
}  // namespace android
+13 −0
Original line number Diff line number Diff line
@@ -701,7 +701,20 @@ rinse_repeat:
    }

    if ((size_t)mPrevBandwidthIndex != bandwidthIndex) {
#ifdef QCOM_HARDWARE
        char value[PROPERTY_VALUE_MAX];
        if(property_get("httplive.enable.discontinuity", value, NULL) &&
           (!strcasecmp(value, "true") || !strcmp(value, "1")) ) {
           bandwidthChanged = true;
           LOGV("discontinuity property set, queue discontinuity");
        }
        else {
           LOGV("BW changed, but do not queue discontinuity");
           bandwidthChanged = false;
        }
#else
        bandwidthChanged = true;
#endif
    }

    if (mPrevBandwidthIndex < 0) {
+39 −2
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@
#include <media/stagefright/MetaData.h>
#include <media/IStreamSource.h>
#include <utils/KeyedVector.h>
#ifdef QCOM_HARDWARE
#include <cutils/properties.h>
#endif

namespace android {

@@ -307,10 +310,44 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) {

        // The only case we can recover from is if we have two streams
        // and they switched PIDs.

        bool success = false;
#ifdef QCOM_HARDWARE
        bool bDiscontinuityOn = false;
        char value[PROPERTY_VALUE_MAX];
        if (property_get("httplive.enable.discontinuity", value, NULL) &&
           (!strcasecmp(value, "true") || !strcmp(value, "1")) ) {
           LOGI("discontinuity property is set");
           bDiscontinuityOn = true;
        }

        if (!bDiscontinuityOn) {
            LOGI("Discontinuity is not enabled, handle PID change");
            //PIDs can change in between due to BW switches
            //Set PID based on stream type
            for (int i = 0; i < infos.size(); i++) {
                for (int j = 0; j < mStreams.size(); j++){

        if (mStreams.size() == 2 && infos.size() == 2) {
                    sp<Stream> stream = mStreams.editValueAt(j);
                    if (infos.itemAt(i).mType == stream->type() &&
                        infos.itemAt(i).mPID != stream->pid()) {

                        LOGI("PID change for stream %d to %d stream type %x",
                           stream->pid(), infos.itemAt(i).mPID, infos.itemAt(i).mType);
                        mStreams.removeItem(stream->pid());
                        stream->setPID(infos.itemAt(i).mPID);
                        mStreams.add(stream->pid(), stream);
                    }
                }
            }
            success = true;
        }
#endif

        if (
#ifdef QCOM_HARDWARE
                !success &&
#endif
                mStreams.size() == 2 && infos.size() == 2) {
            const StreamInfo &info1 = infos.itemAt(0);
            const StreamInfo &info2 = infos.itemAt(1);