void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) { CHECK_LT(portIndex, mPorts.size()); PortInfo *port = &mPorts.editItemAt(portIndex); CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE); CHECK(port->mDef.bEnabled == !enable); if (!enable) { port->mDef.bEnabled = OMX_FALSE; port->mTransition = PortInfo::DISABLING; for (size_t i = 0; i < port->mBuffers.size(); ++i) { BufferInfo *buffer = &port->mBuffers.editItemAt(i); if (buffer->mOwnedByUs) { buffer->mOwnedByUs = false; if (port->mDef.eDir == OMX_DirInput) { notifyEmptyBufferDone(buffer->mHeader); } else { CHECK_EQ(port->mDef.eDir, OMX_DirOutput); notifyFillBufferDone(buffer->mHeader); } } } port->mQueue.clear(); } else { port->mTransition = PortInfo::ENABLING; } checkTransitions(); }
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; } }
void AnatomyOMXComponent::onQueueFilled(OMX_U32 portIndex) { List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); LOGD("onQueueFilled called"); 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; } OMX_U32 decoded_size; decodeBuffer(outHeader->pBuffer, inHeader->pBuffer, inHeader->nSize, &decoded_size); usleep(10000); outHeader->nSize = decoded_size; inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } }
void SimpleSoftOMXComponent::onPortFlush( OMX_U32 portIndex, bool sendFlushComplete) { if (portIndex == OMX_ALL) { for (size_t i = 0; i < mPorts.size(); ++i) { onPortFlush(i, sendFlushComplete); } if (sendFlushComplete) { notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL); } return; } CHECK_LT(portIndex, mPorts.size()); PortInfo *port = &mPorts.editItemAt(portIndex); // Ideally, the port should not in transitioning state when flushing. // However, in error handling case, e.g., the client can't allocate buffers // when it tries to re-enable the port, the port will be stuck in ENABLING. // The client will then transition the component from Executing to Idle, // which leads to flushing ports. At this time, it should be ok to notify // the client of the error and still clear all buffers on the port. if (port->mTransition != PortInfo::NONE) { notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); } for (size_t i = 0; i < port->mBuffers.size(); ++i) { BufferInfo *buffer = &port->mBuffers.editItemAt(i); if (!buffer->mOwnedByUs) { continue; } buffer->mHeader->nFilledLen = 0; buffer->mHeader->nOffset = 0; buffer->mHeader->nFlags = 0; buffer->mOwnedByUs = false; if (port->mDef.eDir == OMX_DirInput) { notifyEmptyBufferDone(buffer->mHeader); } else { CHECK_EQ(port->mDef.eDir, OMX_DirOutput); notifyFillBufferDone(buffer->mHeader); } } port->mQueue.clear(); if (sendFlushComplete) { notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL); onPortFlushCompleted(portIndex); } }
void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); BufferInfo *outInfo = *outQueue.begin(); outQueue.erase(outQueue.begin()); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); outHeader->nTimeStamp = header->nTimeStamp; outHeader->nFlags = header->nFlags; outHeader->nFilledLen = mPictureSize; memcpy(outHeader->pBuffer + outHeader->nOffset, data, mPictureSize); mPicToHeaderMap.removeItem(picId); delete header; outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); }
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 SoftRaw::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; CHECK_GE(outHeader->nAllocLen, inHeader->nFilledLen); memcpy(outHeader->pBuffer, inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen); outHeader->nFlags = inHeader->nFlags; outHeader->nOffset = 0; outHeader->nFilledLen = inHeader->nFilledLen; outHeader->nTimeStamp = inHeader->nTimeStamp; bool sawEOS = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); if (sawEOS) { break; } } }
void SoftOpus::handleEOS() { List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); CHECK(!inQueue.empty() && !outQueue.empty()); BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; mHaveEOS = true; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); ++mInputBufferCount; }
void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); BufferInfo *outInfo = *outQueue.begin(); outQueue.erase(outQueue.begin()); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); outHeader->nTimeStamp = header->nTimeStamp; outHeader->nFlags = header->nFlags; outHeader->nFilledLen = mWidth * mHeight * 3 / 2; uint8_t *dst = outHeader->pBuffer + outHeader->nOffset; const uint8_t *srcY = data; const uint8_t *srcU = srcY + mWidth * mHeight; const uint8_t *srcV = srcU + mWidth * mHeight / 4; size_t srcYStride = mWidth; size_t srcUStride = mWidth / 2; size_t srcVStride = srcUStride; copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride); mPicToHeaderMap.removeItem(picId); delete header; outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); }
void SoftAMR::onQueueFilled(OMX_U32 portIndex) { List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } 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->nOffset == 0) { mAnchorTimeUs = inHeader->nTimeStamp; mNumSamplesOutput = 0; } const uint8_t *inputPtr = inHeader->pBuffer + inHeader->nOffset; int32_t numBytesRead; if (mMode == MODE_NARROW) { numBytesRead = AMRDecode(mState, (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f), (UWord8 *)&inputPtr[1], reinterpret_cast<int16_t *>(outHeader->pBuffer), MIME_IETF); if (numBytesRead == -1) { ALOGE("PV AMR decoder AMRDecode() call failed"); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; return; } ++numBytesRead; // Include the frame type header byte. if (static_cast<size_t>(numBytesRead) > inHeader->nFilledLen) { // This is bad, should never have happened, but did. Abort now. notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; return; } } else {
void SoftAVC::onQueueFilled(OMX_U32 portIndex) { UNUSED(portIndex); if (mSignalledError) { return; } if (mOutputPortSettingsChange != NONE) { return; } List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); /* If input EOS is seen and decoder is not in flush mode, * set the decoder in flush mode. * There can be a case where EOS is sent along with last picture data * In that case, only after decoding that input data, decoder has to be * put in flush. This case is handled here */ if (mReceivedEOS && !mIsInFlush) { setFlushMode(); } while (!outQueue.empty()) { BufferInfo *inInfo; OMX_BUFFERHEADERTYPE *inHeader; BufferInfo *outInfo; OMX_BUFFERHEADERTYPE *outHeader; size_t timeStampIx; inInfo = NULL; inHeader = NULL; if (!mIsInFlush) { if (!inQueue.empty()) { inInfo = *inQueue.begin(); inHeader = inInfo->mHeader; if (inHeader == NULL) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; continue; } } else { break; } } outInfo = *outQueue.begin(); outHeader = outInfo->mHeader; outHeader->nFlags = 0; outHeader->nTimeStamp = 0; outHeader->nOffset = 0; if (inHeader != NULL) { if (inHeader->nFilledLen == 0) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { continue; } mReceivedEOS = true; inHeader = NULL; setFlushMode(); } else if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { mReceivedEOS = true; } } // When there is an init required and the decoder is not in flush mode, // update output port's definition and reinitialize decoder. if (mInitNeeded && !mIsInFlush) { bool portWillReset = false; status_t err = reInitDecoder(mNewWidth, mNewHeight); if (err != OK) { notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); mSignalledError = true; return; } handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); return; } /* Get a free slot in timestamp array to hold input timestamp */ { size_t i; timeStampIx = 0; for (i = 0; i < MAX_TIME_STAMPS; i++) { if (!mTimeStampsValid[i]) { timeStampIx = i; break; } } if (inHeader != NULL) { mTimeStampsValid[timeStampIx] = true; mTimeStamps[timeStampIx] = inHeader->nTimeStamp; } } { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; WORD32 timeDelay, timeTaken; size_t sizeY, sizeUV; setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); // If input dump is enabled, then write to file DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes); GETTIME(&mTimeStart, NULL); /* Compute time elapsed between end of previous decode() * to start of current decode() */ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); IV_API_CALL_STATUS_T status; status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); bool unsupportedDimensions = (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF)); bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); bool unsupportedLevel = (IH264D_UNSUPPORTED_LEVEL == (s_dec_op.u4_error_code & 0xFF)); GETTIME(&mTimeEnd, NULL); /* Compute time taken for decode() */ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); PRINT_TIME("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, s_dec_op.u4_num_bytes_consumed); if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { mFlushNeeded = true; } if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { /* If the input did not contain picture data, then ignore * the associated timestamp */ mTimeStampsValid[timeStampIx] = false; } // This is needed to handle CTS DecoderTest testCodecResetsH264WithoutSurface, // which is not sending SPS/PPS after port reconfiguration and flush to the codec. if (unsupportedDimensions && !mFlushNeeded) { bool portWillReset = false; mNewWidth = s_dec_op.u4_pic_wd; mNewHeight = s_dec_op.u4_pic_ht; status_t err = reInitDecoder(mNewWidth, mNewHeight); if (err != OK) { notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); mSignalledError = true; return; } handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); return; } if (unsupportedLevel && !mFlushNeeded) { mNewLevel = 51; status_t err = reInitDecoder(mNewWidth, mNewHeight); if (err != OK) { notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); mSignalledError = true; return; } setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); return; } // If the decoder is in the changing resolution mode and there is no output present, // that means the switching is done and it's ready to reset the decoder and the plugin. if (mChangingResolution && !s_dec_op.u4_output_present) { mChangingResolution = false; resetDecoder(); resetPlugin(); continue; } if (unsupportedDimensions || resChanged) { mChangingResolution = true; if (mFlushNeeded) { setFlushMode(); } if (unsupportedDimensions) { mNewWidth = s_dec_op.u4_pic_wd; mNewHeight = s_dec_op.u4_pic_ht; mInitNeeded = true; } continue; } if (unsupportedLevel) { if (mFlushNeeded) { setFlushMode(); } mNewLevel = 51; mInitNeeded = true; continue; } if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { uint32_t width = s_dec_op.u4_pic_wd; uint32_t height = s_dec_op.u4_pic_ht; bool portWillReset = false; handlePortSettingsChange(&portWillReset, width, height); if (portWillReset) { resetDecoder(); return; } } if (s_dec_op.u4_output_present) { outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; mTimeStampsValid[s_dec_op.u4_ts] = false; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } else { /* If in flush mode and no output is returned by the codec, * then come out of flush mode */ mIsInFlush = false; /* If EOS was recieved on input port and there is no output * from the codec, then signal EOS on output port */ if (mReceivedEOS) { outHeader->nFilledLen = 0; outHeader->nFlags |= OMX_BUFFERFLAG_EOS; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; resetPlugin(); } } } if (inHeader != NULL) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } } }
void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { UNUSED_UNLESS_VERBOSE(portIndex); ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", 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 > kMaxInputBufferSize) { ALOGE("input buffer too large (%d).", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } assert(mNumChannels != 0); mEncoderWriteData = true; mEncoderReturnedEncodedData = false; mEncoderReturnedNbBytes = 0; mCurrentInputTimeStamp = inHeader->nTimeStamp; const unsigned nbInputFrames = inHeader->nFilledLen / (2 * mNumChannels); const unsigned nbInputSamples = inHeader->nFilledLen / 2; const OMX_S16 * const pcm16 = reinterpret_cast<OMX_S16 *>(inHeader->pBuffer); CHECK_LE(nbInputSamples, 2 * kMaxNumSamplesPerFrame); for (unsigned i=0 ; i < nbInputSamples ; i++) { mInputBufferPcm32[i] = (FLAC__int32) pcm16[i]; } ALOGV(" about to encode %u samples per channel", nbInputFrames); FLAC__bool ok = FLAC__stream_encoder_process_interleaved( mFlacStreamEncoder, mInputBufferPcm32, nbInputFrames /*samples per channel*/ ); if (ok) { if (mEncoderReturnedEncodedData && (mEncoderReturnedNbBytes != 0)) { ALOGV(" dequeueing buffer on output port after writing data"); outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; mEncoderReturnedEncodedData = false; } else { ALOGV(" encoder process_interleaved returned without data to write"); } } else { ALOGE(" error encountered during encoding"); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } }
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); outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); return; } if (inHeader->nOffset == 0) { /*a@nufront start*/ if (inHeader->nTimeStamp != INVALID_TIMESTAMP) /*a@nufront end*/ 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); mConfig->pOutputBuffer = reinterpret_cast<int16_t *>(outHeader->pBuffer); ERROR_CODE decoderErr; if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) != NO_DECODING_ERROR) { LOGV("mp3 decoder returned error %d", decoderErr); if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR || mConfig->outputFrameSize == 0) { LOGE("mp3 decoder returned error %d", decoderErr); if (mConfig->outputFrameSize == 0) { LOGE("Output frame size is 0"); } notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); mSignalledError = true; return; } // 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; } 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; /*a@nufront start*/ mAnchorTimeUs += (mNumFramesOutput * 1000000ll) / mConfig->samplingRate; /*a@nufront end*/ 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 SoftAMRNBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mSignalledError) { return; } List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t); 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" 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 (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 / kSampleRate) / sizeof(int16_t); if (inHeader->nFilledLen == 0) { if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ALOGV("saw input 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 = outHeader->pBuffer + outHeader->nOffset; size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; Frame_Type_3GPP frameType; int res = AMREncode( mEncState, mSidState, (Mode)mMode, mInputFrame, outPtr, &frameType, AMR_TX_WMF); CHECK_GE(res, 0); CHECK_LE((size_t)res, outAvailable); // Convert header byte from WMF to IETF format. outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c; outHeader->nFilledLen = res; 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; } }
void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { UNUSED(portIndex); if (mSignalledError) { return; } if (mOutputPortSettingsChange != NONE) { return; } if (NULL == mCodecCtx) { if (OK != initDecoder()) { ALOGE("Failed to initialize decoder"); notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); mSignalledError = true; return; } } if (outputBufferWidth() != mStride) { /* Set the run-time (dynamic) parameters */ mStride = outputBufferWidth(); setParams(mStride); } List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); while (!outQueue.empty()) { BufferInfo *inInfo; OMX_BUFFERHEADERTYPE *inHeader; BufferInfo *outInfo; OMX_BUFFERHEADERTYPE *outHeader; size_t timeStampIx; inInfo = NULL; inHeader = NULL; if (!mIsInFlush) { if (!inQueue.empty()) { inInfo = *inQueue.begin(); inHeader = inInfo->mHeader; } else { break; } } outInfo = *outQueue.begin(); outHeader = outInfo->mHeader; outHeader->nFlags = 0; outHeader->nTimeStamp = 0; outHeader->nOffset = 0; if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { mReceivedEOS = true; if (inHeader->nFilledLen == 0) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); inHeader = NULL; setFlushMode(); } } /* Get a free slot in timestamp array to hold input timestamp */ { size_t i; timeStampIx = 0; for (i = 0; i < MAX_TIME_STAMPS; i++) { if (!mTimeStampsValid[i]) { timeStampIx = i; break; } } if (inHeader != NULL) { mTimeStampsValid[timeStampIx] = true; mTimeStamps[timeStampIx] = inHeader->nTimeStamp; } } { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; WORD32 timeDelay, timeTaken; size_t sizeY, sizeUV; if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { ALOGE("Decoder arg setup failed"); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; return; } GETTIME(&mTimeStart, NULL); /* Compute time elapsed between end of previous decode() * to start of current decode() */ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); IV_API_CALL_STATUS_T status; status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); bool unsupportedResolution = (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF)); /* Check for unsupported dimensions */ if (unsupportedResolution) { ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight); notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); mSignalledError = true; return; } bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF)); if (allocationFailed) { ALOGE("Allocation failure in decoder"); notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); mSignalledError = true; return; } bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); getVUIParams(); GETTIME(&mTimeEnd, NULL); /* Compute time taken for decode() */ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, s_dec_op.u4_num_bytes_consumed); if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { mFlushNeeded = true; } if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { /* If the input did not contain picture data, then ignore * the associated timestamp */ mTimeStampsValid[timeStampIx] = false; } // If the decoder is in the changing resolution mode and there is no output present, // that means the switching is done and it's ready to reset the decoder and the plugin. if (mChangingResolution && !s_dec_op.u4_output_present) { mChangingResolution = false; resetDecoder(); resetPlugin(); mStride = outputBufferWidth(); setParams(mStride); continue; } if (resChanged) { mChangingResolution = true; if (mFlushNeeded) { setFlushMode(); } continue; } // Combine the resolution change and coloraspects change in one PortSettingChange event // if necessary. if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { uint32_t width = s_dec_op.u4_pic_wd; uint32_t height = s_dec_op.u4_pic_ht; bool portWillReset = false; handlePortSettingsChange(&portWillReset, width, height); if (portWillReset) { resetDecoder(); resetPlugin(); return; } } else if (mUpdateColorAspects) { notify(OMX_EventPortSettingsChanged, kOutputPortIndex, kDescribeColorAspectsIndex, NULL); mUpdateColorAspects = false; return; } if (s_dec_op.u4_output_present) { outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; mTimeStampsValid[s_dec_op.u4_ts] = false; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } else if (mIsInFlush) { /* If in flush mode and no output is returned by the codec, * then come out of flush mode */ mIsInFlush = false; /* If EOS was recieved on input port and there is no output * from the codec, then signal EOS on output port */ if (mReceivedEOS) { outHeader->nFilledLen = 0; outHeader->nFlags |= OMX_BUFFERFLAG_EOS; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; resetPlugin(); } } } /* If input EOS is seen and decoder is not in flush mode, * set the decoder in flush mode. * There can be a case where EOS is sent along with last picture data * In that case, only after decoding that input data, decoder has to be * put in flush. This case is handled here */ if (mReceivedEOS && !mIsInFlush) { setFlushMode(); } // TODO: Handle more than one picture data if (inHeader != NULL) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } } }
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); // 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); 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); 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); 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 SoftRaw::onQueueFilled(OMX_U32 portIndex) { if (mSignalledError) { return; } List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); int64_t timeUs; int set_flag = 0; if(omx_rs_txt != NULL) { fprintf(omx_rs_txt,"SoftRaw inqueue size %d\n",inQueue.size()); fflush(omx_rs_txt); } while (!inQueue.empty() && !outQueue.empty()) { BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; #if WIFI_DISPLAY_ENABLE_RAW if(mStreamSource != NULL && wifidisplay_flag == 1) { int64_t sys_start_time; int64_t raw_start_time; int64_t sys_time; int status; int64_t wifi_time,wifi_sys_time; timeUs = inHeader->nTimeStamp; wifi_time = wifi_sys_time = 0; status = mStreamSource((void *)wifidisplay_addr,&wifi_sys_time,&wifi_time); if(wifi_sys_time == 0 && wifi_time == 0) { if(omx_rs_txt != NULL) { fprintf(omx_rs_txt,"SoftRaw normal dec delay 300 ms start %lld %lld %lld sys %lld timeUs %lld last %lld delta %lld frame_interval %lld\n" ,sys_start_time,start_time,raw_start_time,sys_time,timeUs,last_timeUs,sys_time-sys_start_time-(timeUs - raw_start_time),frame_interval); fflush(omx_rs_txt); } sys_start_time = start_time; raw_start_time = start_timeUs; last_timeUs = inHeader->nTimeStamp; if(status == -1) ALOGD("Error : Streamingsource can't match softraw decoder"); } else { wifi_start_time = wifi_sys_time; wifi_audio_start_time = wifi_time; if(mSampleRate == 0) { ALOGD("samplingRate %d",mSampleRate); return; } frame_interval = ((inHeader->nFilledLen / (2 * mChannelCount)) * 1000 )/ mSampleRate; if(frame_interval == 0 || mSampleRate == 0) { return; } if(start_timeUs == 0) start_timeUs = inHeader->nTimeStamp; sys_time = systemTime(SYSTEM_TIME_MONOTONIC) / 1000; if(start_time == 0) { start_time = sys_time -(inHeader->nTimeStamp - start_timeUs); last_adujst_time = sys_time; } if(start_time > sys_time -(inHeader->nTimeStamp - start_timeUs)) { start_time = sys_time - (inHeader->nTimeStamp - start_timeUs); ALOGV("SOFTRaw start time %lld wifi_start_time %d",start_time,wifi_start_time); } ALOGV("SOFTRaw start time %lld wifi_start_time %lld mConfig->samplingRate %d",start_time,wifi_start_time,mConfig->samplingRate); sys_start_time = wifi_start_time; raw_start_time = wifi_audio_start_time; int retrtptxt; timeUs = inHeader->nTimeStamp; if((retrtptxt = access("data/test/omx_rs_txt_file",0)) == 0) { if(omx_rs_txt == NULL) omx_rs_txt = fopen("data/test/omx_rs_txt.txt","ab"); } { if(sys_start_time + (timeUs - raw_start_time) < sys_time - 100000ll ) { if(last_timeUs < timeUs )//loop tntil the real timeUs catch up with the old setted one , if there is no data,the old setted is also faster than the real timeUs.so it's okay { if(sys_start_time + (timeUs - raw_start_time) < sys_time - 300000ll || (sys_time - last_adujst_time > 20000000ll && sys_start_time + (timeUs - raw_start_time) < sys_time - 100000ll ))//recalculate the timeUs. { if(omx_rs_txt != NULL) { if(sys_time - last_adujst_time > 20000000ll && sys_start_time + (timeUs - raw_start_time) < sys_time - 100000ll && sys_time-sys_start_time-(timeUs - raw_start_time) > 100000ll) fprintf(omx_rs_txt,"SoftRAW adjust start %lld %lld %lld sys %lld %lld timeUs %lld last %lld delta %lld %lld frame_interval %lld\n" ,sys_start_time,start_time,raw_start_time,last_adujst_time,sys_time,timeUs,last_timeUs,sys_time-sys_start_time-(timeUs - raw_start_time), sys_time-last_adujst_time,frame_interval); else fprintf(omx_rs_txt,"SoftRAW before dec delay 300 ms start %lld %lld %lld sys %lld %lld timeUs %lld last %lld delta %lld %lld frame_interval %lld\n" ,sys_start_time,start_time,raw_start_time,last_adujst_time,sys_time,timeUs,last_timeUs,sys_time-sys_start_time-(timeUs - raw_start_time), sys_time-last_adujst_time,frame_interval); fflush(omx_rs_txt); } timeUs +=((sys_time - sys_start_time - (timeUs - raw_start_time) ) / frame_interval) *frame_interval; set_flag = 1; last_adujst_time = sys_time; } else { if(omx_rs_txt != NULL) { fprintf(omx_rs_txt,"SoftRAW before dec delay 100-300 ms start %lld %lld %lld sys %lld %lld timeUs %lld last %lld delta %lld %lld frame_interval %lld\n" ,sys_start_time,start_time,raw_start_time,last_adujst_time,sys_time,timeUs,last_timeUs,sys_time-sys_start_time-(timeUs - raw_start_time), sys_time-last_adujst_time,frame_interval); fflush(omx_rs_txt); } } } else { if(omx_rs_txt != NULL) { fprintf(omx_rs_txt,"SoftRAW before drop start %lld %lld %lld sys %lld %lld timeUs %lld last %lld delta %lld %lld frame_interval %lld\n" ,sys_start_time,start_time,raw_start_time,last_adujst_time,sys_time,timeUs,last_timeUs,sys_time-sys_start_time-(timeUs - raw_start_time), sys_time-last_adujst_time,frame_interval); fflush(omx_rs_txt); } { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); notifyEmptyBufferDone(inHeader); } continue; } } else { if(omx_rs_txt != NULL) { fprintf(omx_rs_txt,"SoftRAW before less than 100ms start %lld %lld %lld sys %lld %lld timeUs %lld last %lld delta %lld %lld frame_interval %lld\n" ,sys_start_time,start_time,raw_start_time,last_adujst_time,sys_time,timeUs,last_timeUs,sys_time-sys_start_time-(timeUs - raw_start_time), sys_time-last_adujst_time,frame_interval); fflush(omx_rs_txt); } } } inHeader->nTimeStamp = timeUs; last_timeUs = timeUs; if(sys_time - last_adujst_time > 20000000ll) last_adujst_time = sys_time; } } else if(mStreamSource == NULL && wifidisplay_flag == 1) ALOGD("wifidisplay error because no streamingsoure"); #endif CHECK_GE(outHeader->nAllocLen, inHeader->nFilledLen); memcpy(outHeader->pBuffer, inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen); #if WIFI_DISPLAY_ENABLE_RAW if(set_flag == 1) memset(outHeader->pBuffer,0, inHeader->nFilledLen); #endif outHeader->nFlags = inHeader->nFlags; outHeader->nOffset = 0; outHeader->nFilledLen = inHeader->nFilledLen; outHeader->nTimeStamp = inHeader->nTimeStamp; bool sawEOS = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); if (sawEOS) { break; } } }
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); } }
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; } }
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; } 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; } }
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; PortInfo *port = editPortInfo(1); OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader; if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); ++mInputBufferCount; 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; if (!mInitialized) { uint8_t *vol_data[1]; int32_t vol_size = 0; vol_data[0] = NULL; if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { 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, mWidth, mHeight, 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); if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } mInitialized = true; if (mode == MPEG4_MODE && portSettingsChanged()) { return; } continue; } if (!mFramesConfigured) { PortInfo *port = editPortInfo(1); OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader; 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; // 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, ×tamp, &tmp, &useExtTimestamp, outHeader->pBuffer) != PV_TRUE) { ALOGE("failed to decode video frame."); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; return; } if (portSettingsChanged()) { 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 = (mWidth * mHeight * 3) / 2; 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; } }
void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); if (mOutputPortSettingsChange != NONE) { return; } if (portIndex == 0 && mInputBufferCount < 2) { BufferInfo *info = *inQueue.begin(); OMX_BUFFERHEADERTYPE *header = info->mHeader; const uint8_t *data = header->pBuffer + header->nOffset; size_t size = header->nFilledLen; ogg_buffer buf; ogg_reference ref; oggpack_buffer bits; makeBitReader( (const uint8_t *)data + 7, size - 7, &buf, &ref, &bits); if (mInputBufferCount == 0) { CHECK(mVi == NULL); mVi = new vorbis_info; vorbis_info_init(mVi); CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits)); } else { CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits)); CHECK(mState == NULL); mState = new vorbis_dsp_state; CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; } inQueue.erase(inQueue.begin()); info->mOwnedByUs = false; notifyEmptyBufferDone(header); ++mInputBufferCount; return; } 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; } int32_t numPageSamples; 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);; ogg_buffer buf; buf.data = inHeader->pBuffer + inHeader->nOffset; buf.size = inHeader->nFilledLen; buf.refcount = 1; buf.ptr.owner = NULL; ogg_reference ref; ref.buffer = &buf; ref.begin = 0; ref.length = buf.size; ref.next = NULL; ogg_packet pack; pack.packet = &ref; pack.bytes = ref.length; pack.b_o_s = 0; pack.e_o_s = 0; pack.granulepos = 0; pack.packetno = 0; int numFrames = 0; int err = vorbis_dsp_synthesis(mState, &pack, 1); if (err != 0) { ALOGW("vorbis_dsp_synthesis returned %d", err); } else { numFrames = vorbis_dsp_pcmout( mState, (int16_t *)outHeader->pBuffer, kMaxNumSamplesPerBuffer); if (numFrames < 0) { ALOGE("vorbis_dsp_pcmout returned %d", numFrames); numFrames = 0; } } if (mNumFramesLeftOnPage >= 0) { if (numFrames > mNumFramesLeftOnPage) { ALOGV("discarding %d frames at end of page", numFrames - mNumFramesLeftOnPage); numFrames = mNumFramesLeftOnPage; } mNumFramesLeftOnPage -= numFrames; } outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels; outHeader->nOffset = 0; outHeader->nFlags = 0; outHeader->nTimeStamp = mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mVi->rate; mNumFramesOutput += numFrames; 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; ++mInputBufferCount; } }
void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex) { int err = 0; 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 (mCtx->width != mWidth || mCtx->height != mHeight) { mCtx->width = mWidth; mCtx->height = mHeight; mStride = mWidth; updatePortDefinitions(); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; return; } 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->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { LOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen); hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen); if (!mExtradataReady && !mIgnoreExtradata) { //if (mMode == MODE_H264) // it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag. // for example, H264, the first input buffer is SPS, and another is PPS! int orig_extradata_size = mCtx->extradata_size; mCtx->extradata_size += inHeader->nFilledLen; mCtx->extradata = (uint8_t *)realloc(mCtx->extradata, mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!mCtx->extradata) { LOGE("ffmpeg video decoder failed to alloc extradata memory."); notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL); mSignalledError = true; return; } memcpy(mCtx->extradata + orig_extradata_size, inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen); memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; continue; } if (mIgnoreExtradata) { LOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen); inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; continue; } } AVPacket pkt; av_init_packet(&pkt); pkt.data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset; pkt.size = inHeader->nFilledLen; pkt.pts = inHeader->nTimeStamp; #if DEBUG_PKT LOGV("pkt size: %d, pts: %lld", pkt.size, pkt.pts); #endif if (!mExtradataReady) { LOGI("extradata is ready"); hexdump(mCtx->extradata, mCtx->extradata_size); LOGI("open ffmpeg decoder now"); mExtradataReady = true; err = avcodec_open2(mCtx, mCtx->codec, NULL); if (err < 0) { LOGE("ffmpeg video decoder failed to initialize. (%d)", err); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; return; } } int gotPic = false; AVFrame *frame = avcodec_alloc_frame(); err = avcodec_decode_video2(mCtx, frame, &gotPic, &pkt); if (err < 0) { LOGE("ffmpeg video decoder failed to decode frame. (%d)", err); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; av_free(frame); return; } if (gotPic) { AVPicture pict; int64_t pts = AV_NOPTS_VALUE; uint8_t *dst = outHeader->pBuffer; memset(&pict, 0, sizeof(AVPicture)); pict.data[0] = dst; pict.data[1] = dst + mStride * mHeight; pict.data[2] = pict.data[1] + (mStride / 2 * mHeight / 2); pict.linesize[0] = mStride; pict.linesize[1] = mStride / 2; pict.linesize[2] = mStride / 2; int sws_flags = SWS_BICUBIC; mImgConvertCtx = sws_getCachedContext(mImgConvertCtx, mWidth, mHeight, mCtx->pix_fmt, mWidth, mHeight, PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL); if (mImgConvertCtx == NULL) { LOGE("Cannot initialize the conversion context"); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; av_free(frame); return; } sws_scale(mImgConvertCtx, frame->data, frame->linesize, 0, mHeight, pict.data, pict.linesize); outHeader->nOffset = 0; outHeader->nFilledLen = (mStride * mHeight * 3) / 2; outHeader->nFlags = 0; if (frame->key_frame) outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; // process timestamps if (decoder_reorder_pts == -1) { pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(), frame, "best_effort_timestamp"); } else if (decoder_reorder_pts) { pts = frame->pkt_pts; } else { pts = frame->pkt_dts; } if (pts == AV_NOPTS_VALUE) { pts = 0; } outHeader->nTimeStamp = pts; #if DEBUG_FRM LOGV("frame pts: %lld", pts); #endif outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; av_free(frame); } }
void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { UNUSED(portIndex); if (mOutputPortSettingsChange != NONE) { return; } List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); /* If input EOS is seen and decoder is not in flush mode, * set the decoder in flush mode. * There can be a case where EOS is sent along with last picture data * In that case, only after decoding that input data, decoder has to be * put in flush. This case is handled here */ if (mReceivedEOS && !mIsInFlush) { setFlushMode(); } while (!outQueue.empty()) { BufferInfo *inInfo; OMX_BUFFERHEADERTYPE *inHeader; BufferInfo *outInfo; OMX_BUFFERHEADERTYPE *outHeader; size_t timeStampIx; inInfo = NULL; inHeader = NULL; if (!mIsInFlush) { if (!inQueue.empty()) { inInfo = *inQueue.begin(); inHeader = inInfo->mHeader; } else { break; } } outInfo = *outQueue.begin(); outHeader = outInfo->mHeader; outHeader->nFlags = 0; outHeader->nTimeStamp = 0; outHeader->nOffset = 0; if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { ALOGD("EOS seen on input"); mReceivedEOS = true; if (inHeader->nFilledLen == 0) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); inHeader = NULL; setFlushMode(); } } // When there is an init required and the decoder is not in flush mode, // update output port's definition and reinitialize decoder. if (mInitNeeded && !mIsInFlush) { bool portWillReset = false; handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); CHECK_EQ(reInitDecoder(), (status_t)OK); return; } /* Get a free slot in timestamp array to hold input timestamp */ { size_t i; timeStampIx = 0; for (i = 0; i < MAX_TIME_STAMPS; i++) { if (!mTimeStampsValid[i]) { timeStampIx = i; break; } } if (inHeader != NULL) { mTimeStampsValid[timeStampIx] = true; mTimeStamps[timeStampIx] = inHeader->nTimeStamp; } } { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; WORD32 timeDelay, timeTaken; size_t sizeY, sizeUV; setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); GETTIME(&mTimeStart, NULL); /* Compute time elapsed between end of previous decode() * to start of current decode() */ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); IV_API_CALL_STATUS_T status; status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); //Fixed if ( mWidth != s_dec_op.u4_pic_wd || mHeight != s_dec_op.u4_pic_ht) { ALOGE("mWidth %d, mHeight %d -> mNewWidth %d, mNewHeight %d", mWidth, mHeight, mNewWidth, mNewHeight); if(mFlushOutBuffer) { ivd_aligned_free(mFlushOutBuffer); mFlushOutBuffer = NULL; } uint32_t bufferSize = s_dec_op.u4_pic_wd * s_dec_op.u4_pic_ht * 3 / 2; mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize); if (NULL == mFlushOutBuffer) { ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize); return; } ALOGE("re-alloc mFlushOutBuffer"); } // FIXME: Compare |status| to IHEVCD_UNSUPPORTED_DIMENSIONS, which is not one of the // IV_API_CALL_STATUS_T, seems be wrong. But this is what the decoder returns right now. // The decoder should be fixed so that |u4_error_code| instead of |status| returns // IHEVCD_UNSUPPORTED_DIMENSIONS. bool unsupportedDimensions = ((IHEVCD_UNSUPPORTED_DIMENSIONS == status) || (IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code)); bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); GETTIME(&mTimeEnd, NULL); /* Compute time taken for decode() */ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, s_dec_op.u4_num_bytes_consumed); if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { mFlushNeeded = true; } if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { /* If the input did not contain picture data, then ignore * the associated timestamp */ mTimeStampsValid[timeStampIx] = false; } // This is needed to handle CTS DecoderTest testCodecResetsHEVCWithoutSurface, // which is not sending SPS/PPS after port reconfiguration and flush to the codec. if (unsupportedDimensions && !mFlushNeeded) { bool portWillReset = false; handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht); CHECK_EQ(reInitDecoder(), (status_t)OK); setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); return; } // If the decoder is in the changing resolution mode and there is no output present, // that means the switching is done and it's ready to reset the decoder and the plugin. if (mChangingResolution && !s_dec_op.u4_output_present) { mChangingResolution = false; resetDecoder(); resetPlugin(); continue; } if (unsupportedDimensions || resChanged) { mChangingResolution = true; if (mFlushNeeded) { setFlushMode(); } if (unsupportedDimensions) { mNewWidth = s_dec_op.u4_pic_wd; mNewHeight = s_dec_op.u4_pic_ht; mInitNeeded = true; } continue; } if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { uint32_t width = s_dec_op.u4_pic_wd; uint32_t height = s_dec_op.u4_pic_ht; bool portWillReset = false; handlePortSettingsChange(&portWillReset, width, height); if (portWillReset) { resetDecoder(); return; } } if (s_dec_op.u4_output_present) { outHeader->nFilledLen = (mWidth * mHeight * 3) / 2; outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; mTimeStampsValid[s_dec_op.u4_ts] = false; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } else { /* If in flush mode and no output is returned by the codec, * then come out of flush mode */ mIsInFlush = false; /* If EOS was recieved on input port and there is no output * from the codec, then signal EOS on output port */ if (mReceivedEOS) { outHeader->nFilledLen = 0; outHeader->nFlags |= OMX_BUFFERFLAG_EOS; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; resetPlugin(); } } } // TODO: Handle more than one picture data if (inHeader != NULL) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } } }
void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) { UNUSED(portIndex); if (mOutputPortSettingsChange != NONE) { return; } List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); /* If input EOS is seen and decoder is not in flush mode, * set the decoder in flush mode. * There can be a case where EOS is sent along with last picture data * In that case, only after decoding that input data, decoder has to be * put in flush. This case is handled here */ if (mReceivedEOS && !mIsInFlush) { setFlushMode(); } while (!outQueue.empty()) { BufferInfo *inInfo; OMX_BUFFERHEADERTYPE *inHeader; BufferInfo *outInfo; OMX_BUFFERHEADERTYPE *outHeader; size_t timeStampIx; inInfo = NULL; inHeader = NULL; if (!mIsInFlush) { if (!inQueue.empty()) { inInfo = *inQueue.begin(); inHeader = inInfo->mHeader; } else { break; } } outInfo = *outQueue.begin(); outHeader = outInfo->mHeader; outHeader->nFlags = 0; outHeader->nTimeStamp = 0; outHeader->nOffset = 0; if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { mReceivedEOS = true; if (inHeader->nFilledLen == 0) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); inHeader = NULL; setFlushMode(); } } // When there is an init required and the decoder is not in flush mode, // update output port's definition and reinitialize decoder. if (mInitNeeded && !mIsInFlush) { bool portWillReset = false; handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); CHECK_EQ(reInitDecoder(), (status_t)OK); return; } /* Get a free slot in timestamp array to hold input timestamp */ { size_t i; timeStampIx = 0; for (i = 0; i < MAX_TIME_STAMPS; i++) { if (!mTimeStampsValid[i]) { timeStampIx = i; break; } } if (inHeader != NULL) { mTimeStampsValid[timeStampIx] = true; mTimeStamps[timeStampIx] = inHeader->nTimeStamp; } } { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; WORD32 timeDelay, timeTaken; size_t sizeY, sizeUV; setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); // If input dump is enabled, then write to file DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes); if (s_dec_ip.u4_num_Bytes > 0) { char *ptr = (char *)s_dec_ip.pv_stream_buffer; } GETTIME(&mTimeStart, NULL); /* Compute time elapsed between end of previous decode() * to start of current decode() */ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); IV_API_CALL_STATUS_T status; status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code); bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); GETTIME(&mTimeEnd, NULL); /* Compute time taken for decode() */ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, s_dec_op.u4_num_bytes_consumed); if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { mFlushNeeded = true; } if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { /* If the input did not contain picture data, then ignore * the associated timestamp */ mTimeStampsValid[timeStampIx] = false; } // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface, // which is not sending SPS/PPS after port reconfiguration and flush to the codec. if (unsupportedDimensions && !mFlushNeeded) { bool portWillReset = false; handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht); CHECK_EQ(reInitDecoder(), (status_t)OK); setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); return; } // If the decoder is in the changing resolution mode and there is no output present, // that means the switching is done and it's ready to reset the decoder and the plugin. if (mChangingResolution && !s_dec_op.u4_output_present) { mChangingResolution = false; resetDecoder(); resetPlugin(); continue; } if (unsupportedDimensions || resChanged) { mChangingResolution = true; if (mFlushNeeded) { setFlushMode(); } if (unsupportedDimensions) { mNewWidth = s_dec_op.u4_pic_wd; mNewHeight = s_dec_op.u4_pic_ht; mInitNeeded = true; } continue; } if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { uint32_t width = s_dec_op.u4_pic_wd; uint32_t height = s_dec_op.u4_pic_ht; bool portWillReset = false; handlePortSettingsChange(&portWillReset, width, height); if (portWillReset) { resetDecoder(); return; } } if (s_dec_op.u4_output_present) { size_t timeStampIdx; outHeader->nFilledLen = (mWidth * mHeight * 3) / 2; timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid); outHeader->nTimeStamp = mTimeStamps[timeStampIdx]; mTimeStampsValid[timeStampIdx] = false; /* mWaitForI waits for the first I picture. Once made FALSE, it has to remain false till explicitly set to TRUE. */ mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type); if (mWaitForI) { s_dec_op.u4_output_present = false; } else { ALOGV("Output timestamp: %lld, res: %ux%u", (long long)outHeader->nTimeStamp, mWidth, mHeight); DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen); outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } } else { /* If in flush mode and no output is returned by the codec, * then come out of flush mode */ mIsInFlush = false; /* If EOS was recieved on input port and there is no output * from the codec, then signal EOS on output port */ if (mReceivedEOS) { outHeader->nFilledLen = 0; outHeader->nFlags |= OMX_BUFFERFLAG_EOS; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; resetPlugin(); } } } // TODO: Handle more than one picture data if (inHeader != NULL) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = 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, ×tamp, &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; } }
void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { if (mOutputPortSettingsChange != NONE) { return; } List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); bool EOSseen = false; 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) { EOSseen = true; if (inHeader->nFilledLen == 0) { 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 (mImg == NULL) { if (vpx_codec_decode( (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, NULL, 0)) { ALOGE("on2 decoder failed to decode frame."); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } vpx_codec_iter_t iter = NULL; mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); } if (mImg != NULL) { CHECK_EQ(mImg->fmt, VPX_IMG_FMT_I420); uint32_t width = mImg->d_w; uint32_t height = mImg->d_h; bool portWillReset = false; handlePortSettingsChange(&portWillReset, width, height); if (portWillReset) { return; } outHeader->nOffset = 0; outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0; outHeader->nTimeStamp = inHeader->nTimeStamp; if (outHeader->nAllocLen >= outHeader->nFilledLen) { uint8_t *dst = outHeader->pBuffer; const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y]; const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U]; const uint8_t *srcV = (const uint8_t *)mImg->planes[VPX_PLANE_V]; size_t srcYStride = mImg->stride[VPX_PLANE_Y]; size_t srcUStride = mImg->stride[VPX_PLANE_U]; size_t srcVStride = mImg->stride[VPX_PLANE_V]; copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride); } else { ALOGE("b/27597103, buffer too small"); outHeader->nFilledLen = 0; } mImg = NULL; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } }