bool ASessionDescription::getDimensions(
        size_t index, unsigned long PT,
        int32_t *width, int32_t *height) const {
    *width = 0;
    *height = 0;

    char key[33];
    snprintf(key, sizeof(key), "a=framesize:%lu", PT);
    if (PT > 9999999) {
        android_errorWriteLog(0x534e4554, "25747670");
    }
    AString value;
    if (!findAttribute(index, key, &value)) {
        return false;
    }

    const char *s = value.c_str();
    char *end;
    *width = strtoul(s, &end, 10);
    CHECK_GT(end, s);
    CHECK_EQ(*end, '-');

    s = end + 1;
    *height = strtoul(s, &end, 10);
    CHECK_GT(end, s);
    CHECK_EQ(*end, '\0');

    return true;
}
bool SoftAVC::setDecodeArgs(
        ivd_video_decode_ip_t *ps_dec_ip,
        ivd_video_decode_op_t *ps_dec_op,
        OMX_BUFFERHEADERTYPE *inHeader,
        OMX_BUFFERHEADERTYPE *outHeader,
        size_t timeStampIx) {
    size_t sizeY = outputBufferWidth() * outputBufferHeight();
    size_t sizeUV;

    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);

    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;

    /* When in flush and after EOS with zero byte input,
     * inHeader is set to zero. Hence check for non-null */
    if (inHeader) {
        ps_dec_ip->u4_ts = timeStampIx;
        ps_dec_ip->pv_stream_buffer =
            inHeader->pBuffer + inHeader->nOffset + mInputOffset;
        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen - mInputOffset;
    } else {
        ps_dec_ip->u4_ts = 0;
        ps_dec_ip->pv_stream_buffer = NULL;
        ps_dec_ip->u4_num_Bytes = 0;
    }

    sizeUV = sizeY / 4;
    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;

    uint8_t *pBuf;
    if (outHeader) {
        if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
            android_errorWriteLog(0x534e4554, "27833616");
            return false;
        }
        pBuf = outHeader->pBuffer;
    } else {
        // mFlushOutBuffer always has the right size.
        pBuf = mFlushOutBuffer;
    }

    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
    return true;
}
Esempio n. 3
0
void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
    if (mSignalledError) {
        return;
    }

    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    if (!mSentCodecSpecificData) {
        // The very first thing we want to output is the codec specific
        // data. It does not require any input data but we will need an
        // output buffer to store it in.

        if (outQueue.empty()) {
            return;
        }

        if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
            ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        OMX_U32 actualBitRate  = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE);
        if (mBitRate != actualBitRate) {
            ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate);
        }

        AACENC_InfoStruct encInfo;
        if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
            ALOGE("Failed to get AAC encoder info");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

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

        if (outHeader->nOffset + encInfo.confSize > outHeader->nAllocLen) {
            ALOGE("b/34617444");
            android_errorWriteLog(0x534e4554,"34617444");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        outHeader->nFilledLen = encInfo.confSize;
        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;

        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
        memcpy(out, encInfo.confBuf, encInfo.confSize);

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

        mSentCodecSpecificData = true;
    }

    size_t numBytesPerInputFrame =
        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);

    // Limit input size so we only get one ELD frame
    if (mAACProfile == OMX_AUDIO_AACObjectELD && numBytesPerInputFrame > 512) {
        numBytesPerInputFrame = 512;
    }

    for (;;) {
        // We do the following until we run out of buffers.

        while (mInputSize < numBytesPerInputFrame) {
            // As long as there's still input data to be read we
            // will drain "kNumSamplesPerFrame * mNumChannels" samples
            // into the "mInputFrame" buffer and then encode those
            // as a unit into an output buffer.

            if (mSawInputEOS || inQueue.empty()) {
                return;
            }

            BufferInfo *inInfo = *inQueue.begin();
            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

            const void *inData = inHeader->pBuffer + inHeader->nOffset;

            size_t copy = numBytesPerInputFrame - mInputSize;
            if (copy > inHeader->nFilledLen) {
                copy = inHeader->nFilledLen;
            }

            if (mInputFrame == NULL) {
                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
                mAllocatedFrameSize = numBytesPerInputFrame;
            } else if (mAllocatedFrameSize != numBytesPerInputFrame) {
                ALOGE("b/34621073: changed size from %d to %d",
                        (int)mAllocatedFrameSize, (int)numBytesPerInputFrame);
                android_errorWriteLog(0x534e4554,"34621073");
                delete mInputFrame;
                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
                mAllocatedFrameSize = numBytesPerInputFrame;

            }

            if (mInputSize == 0) {
                mInputTimeUs = inHeader->nTimeStamp;
            }

            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
            mInputSize += copy;

            inHeader->nOffset += copy;
            inHeader->nFilledLen -= copy;

            // "Time" on the input buffer has in effect advanced by the
            // number of audio frames we just advanced nOffset by.
            inHeader->nTimeStamp +=
                (copy * 1000000ll / mSampleRate)
                    / (mNumChannels * sizeof(int16_t));

            if (inHeader->nFilledLen == 0) {
                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                    mSawInputEOS = true;

                    // Pad any remaining data with zeroes.
                    memset((uint8_t *)mInputFrame + mInputSize,
                           0,
                           numBytesPerInputFrame - mInputSize);

                    mInputSize = numBytesPerInputFrame;
                }

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

                inData = NULL;
                inHeader = NULL;
                inInfo = NULL;
            }
        }

        // At this  point we have all the input data necessary to encode
        // a single frame, all we need is an output buffer to store the result
        // in.

        if (outQueue.empty()) {
            return;
        }

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

        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;

        AACENC_InArgs inargs;
        AACENC_OutArgs outargs;
        memset(&inargs, 0, sizeof(inargs));
        memset(&outargs, 0, sizeof(outargs));
        inargs.numInSamples = numBytesPerInputFrame / sizeof(int16_t);

        void* inBuffer[]        = { (unsigned char *)mInputFrame };
        INT   inBufferIds[]     = { IN_AUDIO_DATA };
        INT   inBufferSize[]    = { (INT)numBytesPerInputFrame };
        INT   inBufferElSize[]  = { sizeof(int16_t) };

        AACENC_BufDesc inBufDesc;
        inBufDesc.numBufs           = sizeof(inBuffer) / sizeof(void*);
        inBufDesc.bufs              = (void**)&inBuffer;
        inBufDesc.bufferIdentifiers = inBufferIds;
        inBufDesc.bufSizes          = inBufferSize;
        inBufDesc.bufElSizes        = inBufferElSize;

        void* outBuffer[]       = { outPtr };
        INT   outBufferIds[]    = { OUT_BITSTREAM_DATA };
        INT   outBufferSize[]   = { 0 };
        INT   outBufferElSize[] = { sizeof(UCHAR) };

        AACENC_BufDesc outBufDesc;
        outBufDesc.numBufs           = sizeof(outBuffer) / sizeof(void*);
        outBufDesc.bufs              = (void**)&outBuffer;
        outBufDesc.bufferIdentifiers = outBufferIds;
        outBufDesc.bufSizes          = outBufferSize;
        outBufDesc.bufElSizes        = outBufferElSize;

        // Encode the mInputFrame, which is treated as a modulo buffer
        AACENC_ERROR encoderErr = AACENC_OK;
        size_t nOutputBytes = 0;

        do {
            memset(&outargs, 0, sizeof(outargs));

            outBuffer[0] = outPtr;
            outBufferSize[0] = outAvailable - nOutputBytes;

            encoderErr = aacEncEncode(mAACEncoder,
                                      &inBufDesc,
                                      &outBufDesc,
                                      &inargs,
                                      &outargs);

            if (encoderErr == AACENC_OK) {
                outPtr += outargs.numOutBytes;
                nOutputBytes += outargs.numOutBytes;

                if (outargs.numInSamples > 0) {
                    int numRemainingSamples = inargs.numInSamples - outargs.numInSamples;
                    if (numRemainingSamples > 0) {
                        memmove(mInputFrame,
                                &mInputFrame[outargs.numInSamples],
                                sizeof(int16_t) * numRemainingSamples);
                    }
                    inargs.numInSamples -= outargs.numInSamples;
                }
            }
        } while (encoderErr == AACENC_OK && inargs.numInSamples > 0);

        outHeader->nFilledLen = nOutputBytes;

        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;

        if (mSawInputEOS) {
            // We also tag this output buffer with EOS if it corresponds
            // to the final input buffer.
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        }

        outHeader->nTimeStamp = mInputTimeUs;

#if 0
        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
              nOutputBytes, mInputTimeUs, outHeader->nFlags);

        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
#endif

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

        outHeader = NULL;
        outInfo = NULL;

        mInputSize = 0;
    }
}
Esempio n. 4
0
void SoftGSM::onQueueFilled(OMX_U32 portIndex) {
    if (mSignalledError) {
        return;
    }

    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    while (!inQueue.empty() && !outQueue.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;
        }

        if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) {
            ALOGE("input buffer too large (%ld).", inHeader->nFilledLen);
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
        }

        if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) {
            ALOGE("input buffer not multiple of 65 (%ld).", inHeader->nFilledLen);
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
        }

        if (outHeader->nAllocLen < (inHeader->nFilledLen / kMSGSMFrameSize) * 320) {
            ALOGE("output buffer is not large enough (%d).", outHeader->nAllocLen);
            android_errorWriteLog(0x534e4554, "27793367");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;

        int n = mSignalledError ? 0 : DecodeGSM(mGsm,
                  reinterpret_cast<int16_t *>(outHeader->pBuffer), inputptr, inHeader->nFilledLen);

        outHeader->nTimeStamp = inHeader->nTimeStamp;
        outHeader->nOffset = 0;
        outHeader->nFilledLen = n * sizeof(int16_t);
        outHeader->nFlags = 0;

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

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        outInfo = NULL;
        notifyFillBufferDone(outHeader);
        outHeader = NULL;
    }
}
Esempio n. 5
0
void SoftOpus::onQueueFilled(OMX_U32 /* portIndex */) {
    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    if (mOutputPortSettingsChange != NONE) {
        return;
    }

    while (!mHaveEOS && !inQueue.empty() && !outQueue.empty()) {
        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

        if (mInputBufferCount < 3) {
            const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
            size_t size = inHeader->nFilledLen;

            if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) {
                handleEOS();
                return;
            }

            if (mInputBufferCount == 0) {
                CHECK(mHeader == NULL);
                mHeader = new OpusHeader();
                memset(mHeader, 0, sizeof(*mHeader));
                if (!ParseOpusHeader(data, size, mHeader)) {
                    ALOGV("Parsing Opus Header failed.");
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                    return;
                }

                uint8_t channel_mapping[kMaxChannels] = {0};
                if (mHeader->channels <= kMaxChannelsWithDefaultLayout) {
                    memcpy(&channel_mapping,
                           kDefaultOpusChannelLayout,
                           kMaxChannelsWithDefaultLayout);
                } else {
                    memcpy(&channel_mapping,
                           mHeader->stream_map,
                           mHeader->channels);
                }

                int status = OPUS_INVALID_STATE;
                mDecoder = opus_multistream_decoder_create(kRate,
                                                           mHeader->channels,
                                                           mHeader->num_streams,
                                                           mHeader->num_coupled,
                                                           channel_mapping,
                                                           &status);
                if (!mDecoder || status != OPUS_OK) {
                    ALOGV("opus_multistream_decoder_create failed status=%s",
                          opus_strerror(status));
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                    return;
                }
                status =
                    opus_multistream_decoder_ctl(mDecoder,
                                                 OPUS_SET_GAIN(mHeader->gain_db));
                if (status != OPUS_OK) {
                    ALOGV("Failed to set OPUS header gain; status=%s",
                          opus_strerror(status));
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                    return;
                }
            } else if (mInputBufferCount == 1) {
                mCodecDelay = ns_to_samples(
                                  *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
                                                               inHeader->nOffset)),
                                  kRate);
                mSamplesToDiscard = mCodecDelay;
            } else {
                mSeekPreRoll = ns_to_samples(
                                   *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
                                                                inHeader->nOffset)),
                                   kRate);
                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                mOutputPortSettingsChange = AWAITING_DISABLED;
            }

            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                handleEOS();
                return;
            }

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

            continue;
        }

        // Ignore CSD re-submissions.
        if (mInputBufferCount >= 3 && (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                handleEOS();
                return;
            }

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

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

        if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
            handleEOS();
            return;
        }

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

        // When seeking to zero, |mCodecDelay| samples has to be discarded
        // instead of |mSeekPreRoll| samples (as we would when seeking to any
        // other timestamp).
        if (inHeader->nTimeStamp == 0) {
            mSamplesToDiscard = mCodecDelay;
        }

        const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
        const uint32_t size = inHeader->nFilledLen;
        size_t frameSize = kMaxOpusOutputPacketSizeSamples;
        if (frameSize > outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels) {
            frameSize = outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels;
            android_errorWriteLog(0x534e4554, "27833616");
        }

        int numFrames = opus_multistream_decode(mDecoder,
                                                data,
                                                size,
                                                (int16_t *)outHeader->pBuffer,
                                                frameSize,
                                                0);
        if (numFrames < 0) {
            ALOGE("opus_multistream_decode returned %d", numFrames);
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            return;
        }

        outHeader->nOffset = 0;
        if (mSamplesToDiscard > 0) {
            if (mSamplesToDiscard > numFrames) {
                mSamplesToDiscard -= numFrames;
                numFrames = 0;
            } else {
                numFrames -= mSamplesToDiscard;
                outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) *
                                     mHeader->channels;
                mSamplesToDiscard = 0;
            }
        }

        outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;

        outHeader->nTimeStamp = mAnchorTimeUs +
                                (mNumFramesOutput * 1000000ll) /
                                kRate;

        mNumFramesOutput += numFrames;

        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
            mHaveEOS = true;
        } else {
            outHeader->nFlags = 0;
        }

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

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        notifyFillBufferDone(outHeader);
    }
}
Esempio n. 6
0
void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
    if (mSignalledError || mOutputPortSettingsChange != NONE) {
        return;
    }

    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    while (!inQueue.empty() && !outQueue.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);

            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) {
            mAnchorTimeUs = inHeader->nTimeStamp;
            mNumFramesOutput = 0;
        }

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

        mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
        mConfig->inputBufferMaxLength = 0;
        mConfig->inputBufferUsedLength = 0;

        mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
        if ((int32)outHeader->nAllocLen < mConfig->outputFrameSize) {
            ALOGE("input buffer too small: got %lu, expected %u",
                outHeader->nAllocLen, mConfig->outputFrameSize);
            android_errorWriteLog(0x534e4554, "27793371");
            notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
            mSignalledError = true;
            return;
        }

        mConfig->pOutputBuffer =
            reinterpret_cast<int16_t *>(outHeader->pBuffer);

        ERROR_CODE decoderErr;
        if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
                != NO_DECODING_ERROR) {
            ALOGV("mp3 decoder returned error %d", decoderErr);

            if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
                        && decoderErr != SIDE_INFO_ERROR) {
                ALOGE("mp3 decoder returned error %d", decoderErr);
                if(decoderErr == SYNCH_LOST_ERROR) {
                    mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
                } else {
                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
                    mSignalledError = true;
                    return;
                }
            }

            if (mConfig->outputFrameSize == 0) {
                mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
            }

            // This is recoverable, just ignore the current frame and
            // play silence instead.
            memset(outHeader->pBuffer,
                   0,
                   mConfig->outputFrameSize * sizeof(int16_t));

            mConfig->inputBufferUsedLength = inHeader->nFilledLen;
        } else if (mConfig->samplingRate != mSamplingRate
                || mConfig->num_channels != mNumChannels) {
            mSamplingRate = mConfig->samplingRate;
            mNumChannels = mConfig->num_channels;

            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
            mOutputPortSettingsChange = AWAITING_DISABLED;
            return;
        }

        if (mIsFirst) {
            mIsFirst = false;
            // The decoder delay is 529 samples, so trim that many samples off
            // the start of the first output buffer. This essentially makes this
            // decoder have zero delay, which the rest of the pipeline assumes.
            outHeader->nOffset =
                kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

            outHeader->nFilledLen =
                mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
        } else {
            outHeader->nOffset = 0;
            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
        }

        outHeader->nTimeStamp =
            mAnchorTimeUs
                + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;

        outHeader->nFlags = 0;

        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;
            inQueue.erase(inQueue.begin());
            inInfo = NULL;
            notifyEmptyBufferDone(inHeader);
            inHeader = NULL;
        }

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        outInfo = NULL;
        notifyFillBufferDone(outHeader);
        outHeader = NULL;
    }
}
void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) {
    if (mSignalledError || mOutputPortSettingsChange != NONE) {
        return;
    }

    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
        if (inHeader == NULL) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
            continue;
        }

        PortInfo *port = editPortInfo(1);

        OMX_BUFFERHEADERTYPE *outHeader =
            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;

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

            ++mInputBufferCount;

            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                outHeader->nFilledLen = 0;
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;

                List<BufferInfo *>::iterator it = outQueue.begin();
                while ((*it)->mHeader != outHeader) {
                    ++it;
                }

                BufferInfo *outInfo = *it;
                outInfo->mOwnedByUs = false;
                outQueue.erase(it);
                outInfo = NULL;

                notifyFillBufferDone(outHeader);
                outHeader = NULL;
            }
            return;
        }

        uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
        uint32_t *start_code = (uint32_t *)bitstream;
        bool volHeader = *start_code == 0xB0010000;
        if (volHeader) {
            PVCleanUpVideoDecoder(mHandle);
            mInitialized = false;
        }

        if (!mInitialized) {
            uint8_t *vol_data[1];
            int32_t vol_size = 0;

            vol_data[0] = NULL;

            if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
                vol_data[0] = bitstream;
                vol_size = inHeader->nFilledLen;
            }

            MP4DecodingMode mode =
                (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;

            Bool success = PVInitVideoDecoder(
                    mHandle, vol_data, &vol_size, 1,
                    outputBufferWidth(), outputBufferHeight(), mode);

            if (!success) {
                ALOGW("PVInitVideoDecoder failed. Unsupported content?");

                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
                return;
            }

            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
            if (mode != actualMode) {
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
                return;
            }

            PVSetPostProcType((VideoDecControls *) mHandle, 0);

            bool hasFrameData = false;
            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
            } else if (volHeader) {
                hasFrameData = true;
            }

            mInitialized = true;

            if (mode == MPEG4_MODE && handlePortSettingsChange()) {
                return;
            }

            if (!hasFrameData) {
                continue;
            }
        }

        if (!mFramesConfigured) {
            PortInfo *port = editPortInfo(1);
            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;

            OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size;
            if ((outHeader->nAllocLen < yFrameSize) ||
                    (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) {
                ALOGE("Too small output buffer for reference frame: %lu bytes",
                        (unsigned long)outHeader->nAllocLen);
                android_errorWriteLog(0x534e4554, "30033990");
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
                return;
            }
            PVSetReferenceYUV(mHandle, outHeader->pBuffer);
            mFramesConfigured = true;
        }

        uint32_t useExtTimestamp = (inHeader->nOffset == 0);

        // decoder deals in ms (int32_t), OMX in us (int64_t)
        // so use fake timestamp instead
        uint32_t timestamp = 0xFFFFFFFF;
        if (useExtTimestamp) {
            mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
            timestamp = mPvTime;
            mPvTime++;
        }

        int32_t bufferSize = inHeader->nFilledLen;
        int32_t tmp = bufferSize;

        OMX_U32 frameSize;
        OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight;
        if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) {
            ALOGE("Frame size too large");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }
        frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2));

        if (outHeader->nAllocLen < frameSize) {
            android_errorWriteLog(0x534e4554, "27833616");
            ALOGE("Insufficient output buffer size");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }
        // The PV decoder is lying to us, sometimes it'll claim to only have
        // consumed a subset of the buffer when it clearly consumed all of it.
        // ignore whatever it says...
        if (PVDecodeVideoFrame(
                    mHandle, &bitstream, &timestamp, &tmp,
                    &useExtTimestamp,
                    outHeader->pBuffer) != PV_TRUE) {
            ALOGE("failed to decode video frame.");

            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
            return;
        }

        // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
        // decoder may detect size change after PVDecodeVideoFrame.
        if (handlePortSettingsChange()) {
            return;
        }

        // decoder deals in ms, OMX in us.
        outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
        mPvToOmxTimeMap.removeItem(timestamp);

        inHeader->nOffset += bufferSize;
        inHeader->nFilledLen = 0;
        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        } else {
            outHeader->nFlags = 0;
        }

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

        ++mInputBufferCount;

        outHeader->nOffset = 0;
        outHeader->nFilledLen = frameSize;

        List<BufferInfo *>::iterator it = outQueue.begin();
        while ((*it)->mHeader != outHeader) {
            ++it;
        }

        BufferInfo *outInfo = *it;
        outInfo->mOwnedByUs = false;
        outQueue.erase(it);
        outInfo = NULL;

        notifyFillBufferDone(outHeader);
        outHeader = NULL;

        ++mNumSamplesOutput;
    }
}