diff options
Diffstat (limited to 'media/libstagefright/codecs/avc')
-rw-r--r-- | media/libstagefright/codecs/avc/dec/Android.mk | 55 | ||||
-rw-r--r-- | media/libstagefright/codecs/avc/dec/SoftAVC.cpp | 690 | ||||
-rw-r--r-- | media/libstagefright/codecs/avc/dec/SoftAVC.h | 109 |
3 files changed, 841 insertions, 13 deletions
diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk index 1b00347..afecdc4 100644 --- a/media/libstagefright/codecs/avc/dec/Android.mk +++ b/media/libstagefright/codecs/avc/dec/Android.mk @@ -3,25 +3,54 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ AVCDecoder.cpp \ - src/avcdec_api.cpp \ - src/avc_bitstream.cpp \ - src/header.cpp \ - src/itrans.cpp \ - src/pred_inter.cpp \ - src/pred_intra.cpp \ - src/residual.cpp \ - src/slice.cpp \ - src/vlc.cpp + src/avcdec_api.cpp \ + src/avc_bitstream.cpp \ + src/header.cpp \ + src/itrans.cpp \ + src/pred_inter.cpp \ + src/pred_intra.cpp \ + src/residual.cpp \ + src/slice.cpp \ + src/vlc.cpp LOCAL_MODULE := libstagefright_avcdec LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/src \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../common/include \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/../common/include \ $(TOP)/frameworks/base/media/libstagefright/include \ - $(TOP)/frameworks/base/include/media/stagefright/openmax + frameworks/base/include/media/stagefright/openmax \ LOCAL_CFLAGS := -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF= include $(BUILD_STATIC_LIBRARY) + +################################################################################ + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + SoftAVC.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/../common/include \ + frameworks/base/media/libstagefright/include \ + frameworks/base/include/media/stagefright/openmax \ + +LOCAL_CFLAGS := -DOSCL_IMPORT_REF= + +LOCAL_STATIC_LIBRARIES := \ + libstagefright_avcdec + +LOCAL_SHARED_LIBRARIES := \ + libstagefright_avc_common \ + libstagefright libstagefright_omx libstagefright_foundation libutils + +LOCAL_MODULE := libstagefright_soft_avcdec +LOCAL_MODULE_TAGS := eng + +include $(BUILD_SHARED_LIBRARY) + diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp new file mode 100644 index 0000000..9f141ac --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftAVC" +#include <utils/Log.h> + +#include "SoftAVC.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> + +#include "avcdec_api.h" +#include "avcdec_int.h" + +namespace android { + +static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 }; + +template<class T> +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +static int32_t Malloc(void *userData, int32_t size, int32_t attrs) { + return reinterpret_cast<int32_t>(malloc(size)); +} + +static void Free(void *userData, int32_t ptr) { + free(reinterpret_cast<void *>(ptr)); +} + +SoftAVC::SoftAVC( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mHandle(new tagAVCHandle), + mInputBufferCount(0), + mWidth(160), + mHeight(120), + mCropLeft(0), + mCropTop(0), + mCropRight(mWidth - 1), + mCropBottom(mHeight - 1), + mSPSSeen(false), + mPPSSeen(false), + mCurrentTimeUs(-1), + mEOSStatus(INPUT_DATA_AVAILABLE), + mOutputPortSettingsChange(NONE) { + initPorts(); + CHECK_EQ(initDecoder(), (status_t)OK); +} + +SoftAVC::~SoftAVC() { + PVAVCCleanUpDecoder(mHandle); + + delete mHandle; + mHandle = NULL; +} + +void SoftAVC::initPorts() { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumInputBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 8192; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainVideo; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC); + def.format.video.pNativeRender = NULL; + def.format.video.nFrameWidth = mWidth; + def.format.video.nFrameHeight = mHeight; + def.format.video.nStride = def.format.video.nFrameWidth; + def.format.video.nSliceHeight = def.format.video.nFrameHeight; + def.format.video.nBitrate = 0; + def.format.video.xFramerate = 0; + def.format.video.bFlagErrorConcealment = OMX_FALSE; + def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; + def.format.video.eColorFormat = OMX_COLOR_FormatUnused; + def.format.video.pNativeWindow = NULL; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumOutputBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainVideo; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW); + def.format.video.pNativeRender = NULL; + def.format.video.nFrameWidth = mWidth; + def.format.video.nFrameHeight = mHeight; + def.format.video.nStride = def.format.video.nFrameWidth; + def.format.video.nSliceHeight = def.format.video.nFrameHeight; + def.format.video.nBitrate = 0; + def.format.video.xFramerate = 0; + def.format.video.bFlagErrorConcealment = OMX_FALSE; + def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; + def.format.video.pNativeWindow = NULL; + + def.nBufferSize = + (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2; + + addPort(def); +} + +status_t SoftAVC::initDecoder() { + memset(mHandle, 0, sizeof(tagAVCHandle)); + mHandle->AVCObject = NULL; + mHandle->userData = this; + mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper; + mHandle->CBAVC_FrameBind = BindFrameWrapper; + mHandle->CBAVC_FrameUnbind = UnbindFrame; + mHandle->CBAVC_Malloc = Malloc; + mHandle->CBAVC_Free = Free; + + return OK; +} + +OMX_ERRORTYPE SoftAVC::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex != 0) { + return OMX_ErrorNoMore; + } + + if (formatParams->nPortIndex == 0) { + formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC; + formatParams->eColorFormat = OMX_COLOR_FormatUnused; + formatParams->xFramerate = 0; + } else { + CHECK_EQ(formatParams->nPortIndex, 1u); + + formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; + formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; + formatParams->xFramerate = 0; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftAVC::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + switch (index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (strncmp((const char *)roleParams->cRole, + "video_decoder.avc", + OMX_MAX_STRINGNAME_SIZE - 1)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex != 0) { + return OMX_ErrorNoMore; + } + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftAVC::getConfig( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexConfigCommonOutputCrop: + { + OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params; + + if (rectParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + rectParams->nLeft = mCropLeft; + rectParams->nTop = mCropTop; + rectParams->nWidth = mCropRight - mCropLeft + 1; + rectParams->nHeight = mCropBottom - mCropTop + 1; + + return OMX_ErrorNone; + } + + default: + return OMX_ErrorUnsupportedIndex; + } +} + +static void findNALFragment( + const OMX_BUFFERHEADERTYPE *inHeader, + const uint8_t **fragPtr, size_t *fragSize) { + const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; + + size_t size = inHeader->nFilledLen; + + CHECK(size >= 4); + CHECK(!memcmp(kStartCode, data, 4)); + + size_t offset = 4; + while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) { + ++offset; + } + + *fragPtr = &data[4]; + if (offset + 3 >= size) { + *fragSize = size - 4; + } else { + *fragSize = offset - 4; + } +} + +void SoftAVC::onQueueFilled(OMX_U32 portIndex) { + if (mOutputPortSettingsChange != NONE) { + return; + } + + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &outQueue = getPortQueue(1); + + if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) { + return; + } + + while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty()) + && outQueue.size() == kNumOutputBuffers) { + if (mEOSStatus == INPUT_EOS_SEEN) { + OMX_BUFFERHEADERTYPE *outHeader; + if (drainOutputBuffer(&outHeader)) { + 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; + } + + BufferInfo *outInfo = *outQueue.begin(); + outHeader = outInfo->mHeader; + + outHeader->nOffset = 0; + outHeader->nFilledLen = 0; + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + outHeader->nTimeStamp = 0; + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + + mEOSStatus = OUTPUT_FRAMES_FLUSHED; + return; + } + + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + + mEOSStatus = INPUT_EOS_SEEN; + continue; + } + + mCurrentTimeUs = inHeader->nTimeStamp; + + const uint8_t *fragPtr; + size_t fragSize; + findNALFragment(inHeader, &fragPtr, &fragSize); + + bool releaseFragment; + OMX_BUFFERHEADERTYPE *outHeader; + status_t err = decodeFragment( + fragPtr, fragSize, + &releaseFragment, &outHeader); + + if (releaseFragment) { + CHECK_GE(inHeader->nFilledLen, fragSize + 4); + + inHeader->nOffset += fragSize + 4; + inHeader->nFilledLen -= fragSize + 4; + + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + inQueue.erase(inQueue.begin()); + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } + } + + if (outHeader != NULL) { + 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; + } + + if (err == INFO_FORMAT_CHANGED) { + return; + } + + if (err != OK) { + notify(OMX_EventError, OMX_ErrorUndefined, err, NULL); + return; + } + } +} + +status_t SoftAVC::decodeFragment( + const uint8_t *fragPtr, size_t fragSize, + bool *releaseFragment, + OMX_BUFFERHEADERTYPE **outHeader) { + *releaseFragment = true; + *outHeader = NULL; + + int nalType; + int nalRefIdc; + AVCDec_Status res = + PVAVCDecGetNALType( + const_cast<uint8_t *>(fragPtr), fragSize, + &nalType, &nalRefIdc); + + if (res != AVCDEC_SUCCESS) { + LOGV("cannot determine nal type"); + return ERROR_MALFORMED; + } + + if (nalType != AVC_NALTYPE_SPS && nalType != AVC_NALTYPE_PPS + && (!mSPSSeen || !mPPSSeen)) { + // We haven't seen SPS or PPS yet. + return OK; + } + + switch (nalType) { + case AVC_NALTYPE_SPS: + { + mSPSSeen = true; + + res = PVAVCDecSeqParamSet( + mHandle, const_cast<uint8_t *>(fragPtr), + fragSize); + + if (res != AVCDEC_SUCCESS) { + return ERROR_MALFORMED; + } + + AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject; + + int32_t width = + (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16; + + int32_t height = + (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16; + + int32_t crop_left, crop_right, crop_top, crop_bottom; + if (pDecVid->seqParams[0]->frame_cropping_flag) + { + crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset; + crop_right = + width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1); + + if (pDecVid->seqParams[0]->frame_mbs_only_flag) + { + crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset; + crop_bottom = + height - + (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1); + } + else + { + crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset; + crop_bottom = + height - + (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1); + } + } else { + crop_bottom = height - 1; + crop_right = width - 1; + crop_top = crop_left = 0; + } + + status_t err = OK; + + if (mWidth != width || mHeight != height) { + mWidth = width; + mHeight = height; + + updatePortDefinitions(); + + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; + + err = INFO_FORMAT_CHANGED; + } + + if (mCropLeft != crop_left + || mCropTop != crop_top + || mCropRight != crop_right + || mCropBottom != crop_bottom) { + mCropLeft = crop_left; + mCropTop = crop_top; + mCropRight = crop_right; + mCropBottom = crop_bottom; + + notify(OMX_EventPortSettingsChanged, + 1, + OMX_IndexConfigCommonOutputCrop, + NULL); + } + + return err; + } + + case AVC_NALTYPE_PPS: + { + mPPSSeen = true; + + res = PVAVCDecPicParamSet( + mHandle, const_cast<uint8_t *>(fragPtr), + fragSize); + + if (res != AVCDEC_SUCCESS) { + LOGV("PVAVCDecPicParamSet returned error %d", res); + return ERROR_MALFORMED; + } + + return OK; + } + + case AVC_NALTYPE_SLICE: + case AVC_NALTYPE_IDR: + { + res = PVAVCDecodeSlice( + mHandle, const_cast<uint8_t *>(fragPtr), + fragSize); + + if (res == AVCDEC_PICTURE_OUTPUT_READY) { + *releaseFragment = false; + + if (!drainOutputBuffer(outHeader)) { + return UNKNOWN_ERROR; + } + + return OK; + } + + if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) { + return OK; + } else { + LOGV("PVAVCDecodeSlice returned error %d", res); + return ERROR_MALFORMED; + } + } + + case AVC_NALTYPE_SEI: + { + res = PVAVCDecSEI( + mHandle, const_cast<uint8_t *>(fragPtr), + fragSize); + + if (res != AVCDEC_SUCCESS) { + return ERROR_MALFORMED; + } + + return OK; + } + + case AVC_NALTYPE_AUD: + case AVC_NALTYPE_FILL: + case AVC_NALTYPE_EOSEQ: + { + return OK; + } + + default: + { + LOGE("Should not be here, unknown nalType %d", nalType); + + return ERROR_MALFORMED; + } + } + + return OK; +} + +bool SoftAVC::drainOutputBuffer(OMX_BUFFERHEADERTYPE **outHeader) { + int32_t index; + int32_t Release; + AVCFrameIO Output; + Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; + AVCDec_Status status = + PVAVCDecGetOutput(mHandle, &index, &Release, &Output); + + if (status != AVCDEC_SUCCESS) { + return false; + } + + PortInfo *port = editPortInfo(1); + CHECK_GE(index, 0); + CHECK_LT((size_t)index, port->mBuffers.size()); + CHECK(port->mBuffers.editItemAt(index).mOwnedByUs); + + *outHeader = port->mBuffers.editItemAt(index).mHeader; + (*outHeader)->nOffset = 0; + (*outHeader)->nFilledLen = port->mDef.nBufferSize; + (*outHeader)->nFlags = 0; + + return true; +} + +void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { + if (portIndex == 0) { + PVAVCDecReset(mHandle); + + mEOSStatus = INPUT_DATA_AVAILABLE; + } +} + +void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { + if (portIndex != 1) { + return; + } + + switch (mOutputPortSettingsChange) { + case NONE: + break; + + case AWAITING_DISABLED: + { + CHECK(!enabled); + mOutputPortSettingsChange = AWAITING_ENABLED; + break; + } + + default: + { + CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); + CHECK(enabled); + mOutputPortSettingsChange = NONE; + break; + } + } +} + +void SoftAVC::updatePortDefinitions() { + OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef; + def->format.video.nFrameWidth = mWidth; + def->format.video.nFrameHeight = mHeight; + def->format.video.nStride = def->format.video.nFrameWidth; + def->format.video.nSliceHeight = def->format.video.nFrameHeight; + + def = &editPortInfo(1)->mDef; + def->format.video.nFrameWidth = mWidth; + def->format.video.nFrameHeight = mHeight; + def->format.video.nStride = def->format.video.nFrameWidth; + def->format.video.nSliceHeight = def->format.video.nFrameHeight; + + def->nBufferSize = + (def->format.video.nFrameWidth + * def->format.video.nFrameHeight * 3) / 2; +} + +// static +int32_t SoftAVC::ActivateSPSWrapper( + void *userData, unsigned int sizeInMbs, unsigned int numBuffers) { + return static_cast<SoftAVC *>(userData)->activateSPS(sizeInMbs, numBuffers); +} + +// static +int32_t SoftAVC::BindFrameWrapper( + void *userData, int32_t index, uint8_t **yuv) { + return static_cast<SoftAVC *>(userData)->bindFrame(index, yuv); +} + +// static +void SoftAVC::UnbindFrame(void *userData, int32_t index) { +} + +int32_t SoftAVC::activateSPS( + unsigned int sizeInMbs, unsigned int numBuffers) { + PortInfo *port = editPortInfo(1); + CHECK_GE(port->mBuffers.size(), numBuffers); + CHECK_GE(port->mDef.nBufferSize, (sizeInMbs << 7) * 3); + + return 1; +} + +int32_t SoftAVC::bindFrame(int32_t index, uint8_t **yuv) { + PortInfo *port = editPortInfo(1); + + CHECK_GE(index, 0); + CHECK_LT((size_t)index, port->mBuffers.size()); + + BufferInfo *outBuffer = + &port->mBuffers.editItemAt(index); + + CHECK(outBuffer->mOwnedByUs); + + outBuffer->mHeader->nTimeStamp = mCurrentTimeUs; + *yuv = outBuffer->mHeader->pBuffer; + + return 1; +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + return new android::SoftAVC(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.h b/media/libstagefright/codecs/avc/dec/SoftAVC.h new file mode 100644 index 0000000..1594b4d --- /dev/null +++ b/media/libstagefright/codecs/avc/dec/SoftAVC.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOFT_AVC_H_ + +#define SOFT_AVC_H_ + +#include "SimpleSoftOMXComponent.h" + +struct tagAVCHandle; + +namespace android { + +struct SoftAVC : public SimpleSoftOMXComponent { + SoftAVC(const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftAVC(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params); + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params); + + virtual OMX_ERRORTYPE getConfig(OMX_INDEXTYPE index, OMX_PTR params); + + virtual void onQueueFilled(OMX_U32 portIndex); + virtual void onPortFlushCompleted(OMX_U32 portIndex); + virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); + +private: + enum { + kNumInputBuffers = 4, + kNumOutputBuffers = 18, + }; + + enum EOSStatus { + INPUT_DATA_AVAILABLE, + INPUT_EOS_SEEN, + OUTPUT_FRAMES_FLUSHED, + }; + + tagAVCHandle *mHandle; + + size_t mInputBufferCount; + + int32_t mWidth, mHeight; + int32_t mCropLeft, mCropTop, mCropRight, mCropBottom; + + bool mSPSSeen, mPPSSeen; + + int64_t mCurrentTimeUs; + + EOSStatus mEOSStatus; + + enum { + NONE, + AWAITING_DISABLED, + AWAITING_ENABLED + } mOutputPortSettingsChange; + + void initPorts(); + status_t initDecoder(); + + status_t decodeFragment( + const uint8_t *fragPtr, size_t fragSize, + bool *releaseFrames, + OMX_BUFFERHEADERTYPE **outHeader); + + void updatePortDefinitions(); + bool drainOutputBuffer(OMX_BUFFERHEADERTYPE **outHeader); + + static int32_t ActivateSPSWrapper( + void *userData, unsigned int sizeInMbs, unsigned int numBuffers); + + static int32_t BindFrameWrapper( + void *userData, int32_t index, uint8_t **yuv); + + static void UnbindFrame(void *userData, int32_t index); + + int32_t activateSPS( + unsigned int sizeInMbs, unsigned int numBuffers); + + int32_t bindFrame(int32_t index, uint8_t **yuv); + + DISALLOW_EVIL_CONSTRUCTORS(SoftAVC); +}; + +} // namespace android + +#endif // SOFT_AVC_H_ + |