void SoftAVC::drainAllOutputBuffers(bool eos) { List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); H264SwDecPicture decodedPicture; if (mHeadersDecoded) { while (!outQueue.empty() && H264SWDEC_PIC_RDY == H264SwDecNextPicture( mHandle, &decodedPicture, eos /* flush */)) { int32_t picId = decodedPicture.picId; uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture; drainOneOutputBuffer(picId, data); } } if (!eos) { return; } while (!outQueue.empty()) { BufferInfo *outInfo = *outQueue.begin(); outQueue.erase(outQueue.begin()); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; outHeader->nTimeStamp = 0; outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); mEOSStatus = OUTPUT_FRAMES_FLUSHED; } }
bool SoftAVC::drainAllOutputBuffers() { List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); H264SwDecPicture decodedPicture; while (!outQueue.empty()) { BufferInfo *outInfo = *outQueue.begin(); outQueue.erase(outQueue.begin()); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; if (mHeadersDecoded && H264SWDEC_PIC_RDY == H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) { int32_t picId = decodedPicture.picId; CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0); memcpy(outHeader->pBuffer + outHeader->nOffset, decodedPicture.pOutputPicture, mPictureSize); OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); outHeader->nTimeStamp = header->nTimeStamp; outHeader->nFlags = header->nFlags; outHeader->nFilledLen = mPictureSize; mPicToHeaderMap.removeItem(picId); delete header; } else if (mFirstPicture) { // Sending the saved output buffer because of dynamic port reconfiguration drainOneOutputBuffer(mFirstPictureId, mFirstPicture); delete[] mFirstPicture; mFirstPicture = NULL; mFirstPictureId = -1; } else { outHeader->nTimeStamp = 0; outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; mEOSStatus = OUTPUT_FRAMES_FLUSHED; } outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); } return true; }
void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) { return; } List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); if (mHeadersDecoded) { // Dequeue any already decoded output frames to free up space // in the output queue. drainAllOutputBuffers(false /* eos */); } H264SwDecRet ret = H264SWDEC_PIC_RDY; bool portWillReset = false; while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty()) && outQueue.size() == kNumOutputBuffers) { if (mEOSStatus == INPUT_EOS_SEEN) { drainAllOutputBuffers(true /* eos */); return; } BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++mPicId; OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE; memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE)); header->nTimeStamp = inHeader->nTimeStamp; header->nFlags = inHeader->nFlags; if (header->nFlags & OMX_BUFFERFLAG_EOS) { mEOSStatus = INPUT_EOS_SEEN; } mPicToHeaderMap.add(mPicId, header); inQueue.erase(inQueue.begin()); H264SwDecInput inPicture; H264SwDecOutput outPicture; memset(&inPicture, 0, sizeof(inPicture)); inPicture.dataLen = inHeader->nFilledLen; inPicture.pStream = inHeader->pBuffer + inHeader->nOffset; inPicture.picId = mPicId; inPicture.intraConcealmentMethod = 1; H264SwDecPicture decodedPicture; while (inPicture.dataLen > 0) { ret = H264SwDecDecode(mHandle, &inPicture, &outPicture); if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY || ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) { inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream); inPicture.pStream = outPicture.pStrmCurrPos; if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) { mHeadersDecoded = true; H264SwDecInfo decoderInfo; CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); SoftVideoDecoderOMXComponent::CropSettingsMode cropSettingsMode = handleCropParams(decoderInfo); handlePortSettingsChange( &portWillReset, decoderInfo.picWidth, decoderInfo.picHeight, cropSettingsMode); } } else { if (portWillReset) { if (H264SwDecNextPicture(mHandle, &decodedPicture, 0) == H264SWDEC_PIC_RDY) { // Save this output buffer; otherwise, it will be // lost during dynamic port reconfiguration because // OpenMAX client will delete _all_ output buffers // in the process. saveFirstOutputBuffer( decodedPicture.picId, (uint8_t *)decodedPicture.pOutputPicture); } } inPicture.dataLen = 0; if (ret < 0) { ALOGE("Decoder failed: %d", ret); notify(OMX_EventError, OMX_ErrorUndefined, ERROR_MALFORMED, NULL); mSignalledError = true; return; } } } inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); if (portWillReset) { return; } if (mFirstPicture && !outQueue.empty()) { drainOneOutputBuffer(mFirstPictureId, mFirstPicture); delete[] mFirstPicture; mFirstPicture = NULL; mFirstPictureId = -1; } drainAllOutputBuffers(false /* eos */); } }