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

Commit c71a9913 authored by Marco Nelissen's avatar Marco Nelissen Committed by Glenn Kasten
Browse files

Fix decoder EOS handling

Conceptually it should be the same whether EOS is signalled on the last
buffer holding data, or an empty buffer that follows. Make it so that
this actually behaves the same for mp3, AAC and Vorbis.

b/8747869

Change-Id: Idece8ef45689a3ffaf70fb45d19862d7b93b2f92
parent 4f53fe74
Loading
Loading
Loading
Loading
+102 −115
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ SoftAAC2::SoftAAC2(
      mIsADTS(false),
      mInputBufferCount(0),
      mSignalledError(false),
      mSawInputEos(false),
      mSignalledOutputEos(false),
      mAnchorTimeUs(0),
      mNumSamplesOutput(0),
      mOutputPortSettingsChange(NONE) {
@@ -350,65 +352,30 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
        return;
    }

    while (!inQueue.empty() && !outQueue.empty()) {
        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
        BufferInfo *inInfo = NULL;
        OMX_BUFFERHEADERTYPE *inHeader = NULL;
        if (!inQueue.empty()) {
            inInfo = *inQueue.begin();
            inHeader = inInfo->mHeader;
        }

        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;

        if (inHeader) {
            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
            notifyEmptyBufferDone(inHeader);

            if (mDecoderHasData) {
                // flush out the decoder's delayed data by calling DecodeFrame
                // one more time, with the AACDEC_FLUSH flag set
                INT_PCM *outBuffer =
                        reinterpret_cast<INT_PCM *>(
                                outHeader->pBuffer + outHeader->nOffset);

                AAC_DECODER_ERROR decoderErr =
                    aacDecoder_DecodeFrame(mAACDecoder,
                                           outBuffer,
                                           outHeader->nAllocLen,
                                           AACDEC_FLUSH);
                mDecoderHasData = false;

                if (decoderErr != AAC_DEC_OK) {
                    mSignalledError = true;

                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
                           NULL);

                    return;
                mSawInputEos = true;
            }

                outHeader->nFilledLen =
                        mStreamInfo->frameSize
                            * sizeof(int16_t)
                            * mStreamInfo->numChannels;
            } else {
                // we never submitted any data to the decoder, so there's nothing to flush out
                outHeader->nFilledLen = 0;
            }

            outHeader->nFlags = OMX_BUFFERFLAG_EOS;

            outQueue.erase(outQueue.begin());
            outInfo->mOwnedByUs = false;
            notifyFillBufferDone(outHeader);
            return;
        }

        if (inHeader->nOffset == 0) {
            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
                mAnchorTimeUs = inHeader->nTimeStamp;
                mNumSamplesOutput = 0;
            }

        size_t adtsHeaderSize = 0;
            if (mIsADTS) {
                size_t adtsHeaderSize = 0;
                // skip 30 bits, aac_frame_length follows.
                // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????

@@ -460,6 +427,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                inBufferLength[0] = inHeader->nFilledLen;
            }
        } else {
            inBufferLength[0] = 0;
        }

        // Fill and decode
        INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(
@@ -471,26 +441,41 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
        int prevNumChannels = mStreamInfo->numChannels;

        AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
        while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
        while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
            mDecoderHasData |= (bytesValid[0] > 0);
            aacDecoder_Fill(mAACDecoder,
                            inBuffer,
                            inBufferLength,
                            bytesValid);
            mDecoderHasData = true;

            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                                outBuffer,
                                                outHeader->nAllocLen,
                                                0 /* flags */);

            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
                if (mSawInputEos && bytesValid[0] <= 0) {
                    if (mDecoderHasData) {
                        // flush out the decoder's delayed data by calling DecodeFrame
                        // one more time, with the AACDEC_FLUSH flag set
                        decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                                            outBuffer,
                                                            outHeader->nAllocLen,
                                                            AACDEC_FLUSH);
                        mDecoderHasData = false;
                    }
                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                    mSignalledOutputEos = true;
                    break;
                } else {
                    ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
                }
            }
        }

        size_t numOutBytes =
            mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;

        if (inHeader) {
            if (decoderErr == AAC_DEC_OK) {
                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
                inHeader->nFilledLen -= inBufferUsedLength;
@@ -516,6 +501,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
            }
        }

        /*
         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
@@ -555,7 +541,6 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
            // we've previously decoded valid data, in the latter case
            // (decode failed) we'll output a silent frame.
            outHeader->nFilledLen = numOutBytes;
            outHeader->nFlags = 0;

            outHeader->nTimeStamp =
                mAnchorTimeUs
@@ -606,6 +591,8 @@ void SoftAAC2::onReset() {
    mStreamInfo->sampleRate = 0;

    mSignalledError = false;
    mSawInputEos = false;
    mSignalledOutputEos = false;
    mOutputPortSettingsChange = NONE;
}

+2 −0
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ private:
    bool mDecoderHasData;
    size_t mInputBufferCount;
    bool mSignalledError;
    bool mSawInputEos;
    bool mSignalledOutputEos;
    int64_t mAnchorTimeUs;
    int64_t mNumSamplesOutput;

+61 −53
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ SoftMP3::SoftMP3(
      mNumChannels(2),
      mSamplingRate(44100),
      mSignalledError(false),
      mSawInputEos(false),
      mSignalledOutputEos(false),
      mOutputPortSettingsChange(NONE) {
    initPorts();
    initDecoder();
@@ -194,48 +196,36 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    while (!inQueue.empty() && !outQueue.empty()) {
        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
        BufferInfo *inInfo = NULL;
        OMX_BUFFERHEADERTYPE *inHeader = NULL;
        if (!inQueue.empty()) {
            inInfo = *inQueue.begin();
            inHeader = inInfo->mHeader;
        }

        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;

        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
            notifyEmptyBufferDone(inHeader);

            if (!mIsFirst) {
                // pad the end of the stream with 529 samples, since that many samples
                // were trimmed off the beginning when decoding started
                outHeader->nFilledLen =
                    kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

                memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
            } else {
                // Since we never discarded frames from the start, we won't have
                // to add any padding at the end either.
                outHeader->nFilledLen = 0;
            }

            outHeader->nFlags = OMX_BUFFERFLAG_EOS;

            outQueue.erase(outQueue.begin());
            outInfo->mOwnedByUs = false;
            notifyFillBufferDone(outHeader);
            return;
        }

        if (inHeader->nOffset == 0) {
        if (inHeader) {
            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
                mAnchorTimeUs = inHeader->nTimeStamp;
                mNumFramesOutput = 0;
            }

            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                mSawInputEos = true;
            }

            mConfig->pInputBuffer =
                inHeader->pBuffer + inHeader->nOffset;

            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
        } else {
            mConfig->pInputBuffer = NULL;
            mConfig->inputBufferCurrentLength = 0;
        }
        mConfig->inputBufferMaxLength = 0;
        mConfig->inputBufferUsedLength = 0;

@@ -262,13 +252,28 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
                mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
            }

            if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
                if (!mIsFirst) {
                    // pad the end of the stream with 529 samples, since that many samples
                    // were trimmed off the beginning when decoding started
                    outHeader->nOffset = 0;
                    outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
                }
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                mSignalledOutputEos = true;
            } else {
                // This is recoverable, just ignore the current frame and
                // play silence instead.
                memset(outHeader->pBuffer,
                       0,
                       mConfig->outputFrameSize * sizeof(int16_t));

                if (inHeader) {
                    mConfig->inputBufferUsedLength = inHeader->nFilledLen;
                }
            }
        } else if (mConfig->samplingRate != mSamplingRate
                || mConfig->num_channels != mNumChannels) {
            mSamplingRate = mConfig->samplingRate;
@@ -289,7 +294,7 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {

            outHeader->nFilledLen =
                mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
        } else {
        } else if (!mSignalledOutputEos) {
            outHeader->nOffset = 0;
            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
        }
@@ -298,14 +303,12 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
            mAnchorTimeUs
                + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;

        outHeader->nFlags = 0;

        if (inHeader) {
            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);

            inHeader->nOffset += mConfig->inputBufferUsedLength;
            inHeader->nFilledLen -= mConfig->inputBufferUsedLength;

        mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;

            if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
@@ -314,6 +317,9 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
            }
        }

        mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
@@ -362,6 +368,8 @@ void SoftMP3::onReset() {
    pvmp3_InitDecoder(mConfig, mDecoderBuf);
    mIsFirst = true;
    mSignalledError = false;
    mSawInputEos = false;
    mSignalledOutputEos = false;
    mOutputPortSettingsChange = NONE;
}

+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ private:

    bool mIsFirst;
    bool mSignalledError;
    bool mSawInputEos;
    bool mSignalledOutputEos;

    enum {
        NONE,
+44 −35
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ SoftVorbis::SoftVorbis(
      mAnchorTimeUs(0),
      mNumFramesOutput(0),
      mNumFramesLeftOnPage(-1),
      mSawInputEos(false),
      mSignalledOutputEos(false),
      mOutputPortSettingsChange(NONE) {
    initPorts();
    CHECK_EQ(initDecoder(), (status_t)OK);
@@ -290,48 +292,47 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
        return;
    }

    while (!inQueue.empty() && !outQueue.empty()) {
        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
        BufferInfo *inInfo = NULL;
        OMX_BUFFERHEADERTYPE *inHeader = NULL;
        if (!inQueue.empty()) {
            inInfo = *inQueue.begin();
            inHeader = inInfo->mHeader;
        }

        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
            notifyEmptyBufferDone(inHeader);

            outHeader->nFilledLen = 0;
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        int32_t numPageSamples = 0;

            outQueue.erase(outQueue.begin());
            outInfo->mOwnedByUs = false;
            notifyFillBufferDone(outHeader);
            return;
        if (inHeader) {
            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                mSawInputEos = true;
            }

        int32_t numPageSamples;
            if (inHeader->nFilledLen || !mSawInputEos) {
                CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
                memcpy(&numPageSamples,
                       inHeader->pBuffer
                        + inHeader->nOffset + inHeader->nFilledLen - 4,
                       sizeof(numPageSamples));

        if (numPageSamples >= 0) {
            mNumFramesLeftOnPage = numPageSamples;
        }

                if (inHeader->nOffset == 0) {
                    mAnchorTimeUs = inHeader->nTimeStamp;
                    mNumFramesOutput = 0;
                }

                inHeader->nFilledLen -= sizeof(numPageSamples);;
            }
        }

        if (numPageSamples >= 0) {
            mNumFramesLeftOnPage = numPageSamples;
        }

        ogg_buffer buf;
        buf.data = inHeader->pBuffer + inHeader->nOffset;
        buf.size = inHeader->nFilledLen;
        buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
        buf.size = inHeader ? inHeader->nFilledLen : 0;
        buf.refcount = 1;
        buf.ptr.owner = NULL;

@@ -351,6 +352,7 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {

        int numFrames = 0;

        outHeader->nFlags = 0;
        int err = vorbis_dsp_synthesis(mState, &pack, 1);
        if (err != 0) {
            ALOGW("vorbis_dsp_synthesis returned %d", err);
@@ -370,13 +372,16 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
                ALOGV("discarding %d frames at end of page",
                     numFrames - mNumFramesLeftOnPage);
                numFrames = mNumFramesLeftOnPage;
                if (mSawInputEos) {
                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                    mSignalledOutputEos = true;
                }
            }
            mNumFramesLeftOnPage -= numFrames;
        }

        outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
        outHeader->nOffset = 0;
        outHeader->nFlags = 0;

        outHeader->nTimeStamp =
            mAnchorTimeUs
@@ -384,11 +389,13 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {

        mNumFramesOutput += numFrames;

        if (inHeader) {
            inInfo->mOwnedByUs = false;
            inQueue.erase(inQueue.begin());
            inInfo = NULL;
            notifyEmptyBufferDone(inHeader);
            inHeader = NULL;
        }

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
@@ -425,6 +432,8 @@ void SoftVorbis::onReset() {
        mVi = NULL;
    }

    mSawInputEos = false;
    mSignalledOutputEos = false;
    mOutputPortSettingsChange = NONE;
}

Loading