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

Commit c2c49ffa authored by Marco Nelissen's avatar Marco Nelissen Committed by android-build-merger
Browse files

Fix flac encoder and decoder EOS handling

am: 103f5a62

Change-Id: Ia42373fdf1f4b227082f6ce2575c82acc7cf1f8e
parents e5f99eeb 103f5a62
Loading
Loading
Loading
Loading
+77 −71
Original line number Diff line number Diff line
@@ -45,9 +45,11 @@ SoftFlacDecoder::SoftFlacDecoder(
        OMX_COMPONENTTYPE **component)
    : SimpleSoftOMXComponent(name, callbacks, appData, component),
      mFLACDecoder(NULL),
      mHasStreamInfo(false),
      mInputBufferCount(0),
      mHasStreamInfo(false),
      mSignalledError(false),
      mSawInputEOS(false),
      mFinishedDecoder(false),
      mOutputPortSettingsChange(NONE) {
    ALOGV("ctor:");
    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
@@ -292,7 +294,6 @@ bool SoftFlacDecoder::isConfigured() const {
}

void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) {
    ALOGV("onQueueFilled:");
    if (mSignalledError || mOutputPortSettingsChange != NONE) {
        return;
    }
@@ -300,35 +301,31 @@ void SoftFlacDecoder::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;
    ALOGV("onQueueFilled %d/%d:", inQueue.empty(), outQueue.empty());
    while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty()) {
        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
        short *outBuffer = reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
        size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
        int64_t timeStamp = 0;

        if (!inQueue.empty()) {
            BufferInfo *inInfo = *inQueue.begin();
            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
            uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
            uint32_t inBufferLength = inHeader->nFilledLen;
        bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;

        if (inHeader->nFilledLen == 0) {
            if (endOfInput) {
                outHeader->nFilledLen = 0;
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                outInfo->mOwnedByUs = false;
                outQueue.erase(outQueue.begin());
                notifyFillBufferDone(outHeader);
            } else {
                ALOGE("onQueueFilled: emptyInputBuffer received");
            }
            inInfo->mOwnedByUs = false;
            inQueue.erase(inQueue.begin());
            notifyEmptyBufferDone(inHeader);
            return;
            ALOGV("input: %u bytes", inBufferLength);
            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                ALOGV("saw EOS");
                mSawInputEOS = true;
            }

            if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
                ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
                inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
            }
            if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
                ALOGV("received config buffer of size %u", inBufferLength);
                status_t decoderErr = mFLACDecoder->parseMetadata(inBuffer, inBufferLength);
                mInputBufferCount++;

@@ -361,10 +358,6 @@ void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) {
                return;
            }

        short *outBuffer =
                reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
        size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;

            status_t decoderErr = mFLACDecoder->decodeOneFrame(
                    inBuffer, inBufferLength, outBuffer, &outBufferSize);
            if (decoderErr != OK) {
@@ -375,21 +368,34 @@ void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) {
            }

            mInputBufferCount++;
        int64_t ts = inHeader->nTimeStamp;
            timeStamp = inHeader->nTimeStamp;
            inInfo->mOwnedByUs = false;
            inQueue.erase(inQueue.begin());
            notifyEmptyBufferDone(inHeader);

        if (endOfInput) {
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        } else if (outBufferSize == 0) {
            if (outBufferSize == 0) {
                ALOGV("no output, trying again");
                continue;
            }
        } else if (mSawInputEOS && !mFinishedDecoder) {
            status_t decoderErr = mFLACDecoder->decodeOneFrame(NULL, 0, outBuffer, &outBufferSize);
            mFinishedDecoder = true;
            if (decoderErr != OK) {
                ALOGE("onQueueFilled: FLACDecoder finish returns error %d", decoderErr);
                mSignalledError = true;
                notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
                return;
            }
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        } else {
            outHeader->nFlags = 0;
            ALOGE("no input buffer but did not get EOS");
            mSignalledError = true;
            notify(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL);
            return;
        }

        outHeader->nFilledLen = outBufferSize;
        outHeader->nTimeStamp = ts;
        outHeader->nTimeStamp = timeStamp;

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
+3 −1
Original line number Diff line number Diff line
@@ -52,9 +52,11 @@ private:

    FLACDecoder *mFLACDecoder;
    FLAC__StreamMetadata_StreamInfo mStreamInfo;
    bool mHasStreamInfo;
    size_t mInputBufferCount;
    bool mHasStreamInfo;
    bool mSignalledError;
    bool mSawInputEOS;
    bool mFinishedDecoder;

    enum {
        NONE,
+85 −61
Original line number Diff line number Diff line
@@ -56,12 +56,13 @@ SoftFlacEncoder::SoftFlacEncoder(
      mCompressionLevel(FLAC_COMPRESSION_LEVEL_DEFAULT),
      mEncoderWriteData(false),
      mEncoderReturnedEncodedData(false),
      mSawInputEOS(false),
      mSentOutputEOS(false),
      mEncoderReturnedNbBytes(0),
      mInputBufferPcm32(NULL)
#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
      , mHeaderOffset(0)
      , mWroteHeader(false)
#endif
      mInputBufferPcm32(NULL),
      mHeaderOffset(0),
      mHeaderComplete(false),
      mWroteHeader(false)
{
    ALOGV("SoftFlacEncoder::SoftFlacEncoder(name=%s)", name);
    initPorts();
@@ -354,26 +355,16 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    while (!inQueue.empty() && !outQueue.empty()) {
    FLAC__bool ok = true;

    while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty()) {
        if (!inQueue.empty()) {
            BufferInfo *inInfo = *inQueue.begin();
            OMX_BUFFERHEADERTYPE *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;

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

            return;
                ALOGV("saw EOS on buffer of size %u", inHeader->nFilledLen);
                mSawInputEOS = true;
            }

            if (inHeader->nFilledLen > kMaxInputBufferSize) {
@@ -398,11 +389,21 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
                mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
            }
            ALOGV(" about to encode %u samples per channel", nbInputFrames);
        FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
            ok = FLAC__stream_encoder_process_interleaved(
                            mFlacStreamEncoder,
                            mInputBufferPcm32,
                            nbInputFrames /*samples per channel*/ );

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

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

        if (ok) {
            if (mEncoderReturnedEncodedData && (mEncoderReturnedNbBytes != 0)) {
                ALOGV(" dequeueing buffer on output port after writing data");
@@ -414,6 +415,21 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
                mEncoderReturnedEncodedData = false;
            } else {
                ALOGV(" encoder process_interleaved returned without data to write");
                if (mSawInputEOS && !mSentOutputEOS) {
                    ALOGV("finishing encoder");
                    mSentOutputEOS = true;
                    FLAC__stream_encoder_finish(mFlacStreamEncoder);
                    if (mEncoderReturnedEncodedData && (mEncoderReturnedNbBytes != 0)) {
                        ALOGV(" dequeueing residual buffer on output port after writing data");
                        outInfo->mOwnedByUs = false;
                        outQueue.erase(outQueue.begin());
                        outInfo = NULL;
                        outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                        notifyFillBufferDone(outHeader);
                        outHeader = NULL;
                        mEncoderReturnedEncodedData = false;
                    }
                }
            }
        } else {
            ALOGE(" error encountered during encoding");
@@ -422,11 +438,6 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
            return;
        }

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

@@ -438,16 +449,22 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
    ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)",
            bytes, samples, current_frame);

#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    if (samples == 0) {
        ALOGI(" saving %zu bytes of header", bytes);
        ALOGV("saving %zu bytes of header", bytes);
        if (mHeaderOffset + bytes > sizeof(mHeader) || mHeaderComplete) {
            ALOGW("header is too big, or header already received");
            mSignalledError = true;
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
        } else {
            memcpy(mHeader + mHeaderOffset, buffer, bytes);
            mHeaderOffset += bytes;// will contain header size when finished receiving header
            if (buffer[0] & 0x80) {
                mHeaderComplete = true;
            }
        }
        return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    }

#endif

    if ((samples == 0) || !mEncoderWriteData) {
        // called by the encoder because there's header data to save, but it's not the role
        // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
@@ -460,16 +477,23 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
    BufferInfo *outInfo = *outQueue.begin();
    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    if (!mWroteHeader) {
        ALOGI(" writing %d bytes of header on output port", mHeaderOffset);
    if (mHeaderComplete && !mWroteHeader) {
        ALOGV(" writing %d bytes of header on output port", mHeaderOffset);
        memcpy(outHeader->pBuffer + outHeader->nOffset + outHeader->nFilledLen,
                mHeader, mHeaderOffset);
        outHeader->nFilledLen += mHeaderOffset;
        outHeader->nOffset    += mHeaderOffset;
        mWroteHeader = true;
        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
        notifyFillBufferDone(outHeader);
        outInfo = NULL;
        outHeader = NULL;
        // get the next buffer for the rest of the data
        CHECK(!outQueue.empty());
        outInfo = *outQueue.begin();
        outHeader = outInfo->mHeader;
    }
#endif

    // write encoded data
    ALOGV(" writing %zu bytes of encoded data on output port", bytes);
+3 −6
Original line number Diff line number Diff line
@@ -22,10 +22,6 @@

#include "FLAC/stream_encoder.h"

// use this symbol to have the first output buffer start with FLAC frame header so a dump of
// all the output buffers can be opened as a .flac file
//#define WRITE_FLAC_HEADER_IN_FIRST_BUFFER

namespace android {

struct SoftFlacEncoder : public SimpleSoftOMXComponent {
@@ -62,6 +58,8 @@ private:
    // should the data received by the callback be written to the output port
    bool        mEncoderWriteData;
    bool        mEncoderReturnedEncodedData;
    bool        mSawInputEOS;
    bool        mSentOutputEOS;
    size_t      mEncoderReturnedNbBytes;
    OMX_TICKS  mCurrentInputTimeStamp;

@@ -85,11 +83,10 @@ private:
    // before passing the input data to the encoder
    FLAC__int32* mInputBufferPcm32;

#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    unsigned mHeaderOffset;
    bool mHeaderComplete;
    bool mWroteHeader;
    char mHeader[128];
#endif

    DISALLOW_EVIL_CONSTRUCTORS(SoftFlacEncoder);
};
+6 −12
Original line number Diff line number Diff line
@@ -423,23 +423,17 @@ status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen
        short *outBuffer, size_t *outBufferLen) {
    ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);

    if (inBufferLen == 0) {
        ALOGV("decodeOneFrame: no input data");
        if (outBufferLen) {
            *outBufferLen = 0;
        }
        return OK;
    }

    if (!mStreamInfoValid) {
        ALOGW("decodeOneFrame: no streaminfo metadata block");
    }

    if (inBufferLen != 0) {
        status_t err = addDataToBuffer(inBuffer, inBufferLen);
        if (err != OK) {
            ALOGW("decodeOneFrame: addDataToBuffer returns error %d", err);
            return err;
        }
    }

    mWriteRequested = true;
    mWriteCompleted = false;