diff options
author | Yuanjun Huang <yuanjun.huang@intel.com> | 2015-07-14 17:15:49 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-07-14 17:15:49 +0000 |
commit | 1fda5d920dedd63a6b799ba7cb7d824805c73c16 (patch) | |
tree | a1d3957e941e52ba4877588f74fa715cd34ce196 | |
parent | 093da74f74457c1c5e1b9dd60e52103f8d378a97 (diff) | |
parent | 9042795f805dffc0be5b900df3e42fe32ae61349 (diff) | |
download | utils-1fda5d920dedd63a6b799ba7cb7d824805c73c16.tar.gz |
am 9042795f: Implement codec level media resource manager.
* commit '9042795f805dffc0be5b900df3e42fe32ae61349':
Implement codec level media resource manager.
-rw-r--r-- | ISV/Android.mk | 4 | ||||
-rw-r--r-- | ISV/include/isv_omxcomponent.h | 2 | ||||
-rw-r--r-- | ISV/omx/isv_omxcomponent.cpp | 15 | ||||
-rw-r--r-- | ISV/omx/isv_omxcore.cpp | 25 | ||||
-rw-r--r-- | media_resource_manager/Android.mk | 16 | ||||
-rw-r--r-- | media_resource_manager/arbitrator/Android.mk | 24 | ||||
-rw-r--r-- | media_resource_manager/arbitrator/MediaResourceArbitrator.cpp | 541 | ||||
-rw-r--r-- | media_resource_manager/arbitrator/MediaResourceArbitrator.h | 179 | ||||
-rw-r--r-- | media_resource_manager/omx_adaptor/Android.mk | 26 | ||||
-rw-r--r-- | media_resource_manager/omx_adaptor/OMX_adaptor.cpp | 287 | ||||
-rw-r--r-- | media_resource_manager/omx_adaptor/OMX_adaptor.h | 117 | ||||
-rw-r--r-- | media_resource_manager/test/Android.mk | 23 | ||||
-rw-r--r-- | media_resource_manager/test/MediaResourceManager_test.cpp | 122 |
13 files changed, 1379 insertions, 2 deletions
diff --git a/ISV/Android.mk b/ISV/Android.mk index 12965a9..9808e6e 100644 --- a/ISV/Android.mk +++ b/ISV/Android.mk @@ -22,7 +22,8 @@ LOCAL_SHARED_LIBRARIES := \ libhardware \ libexpat \ libva \ - libva-android + libva-android \ + libmrm_omx_adaptor \ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ @@ -32,6 +33,7 @@ LOCAL_C_INCLUDES := \ $(TARGET_OUT_HEADERS)/khronos/openmax \ $(TARGET_OUT_HEADERS)/libva \ $(TARGET_OUT_HEADERS)/pvr/hal \ + $(TARGET_OUT_HEADERS)/media_resource_manager/ \ $(call include-path-for, frameworks-native)/media/openmax ifeq ($(USE_MEDIASDK),true) diff --git a/ISV/include/isv_omxcomponent.h b/ISV/include/isv_omxcomponent.h index 5acea30..1e8d13e 100644 --- a/ISV/include/isv_omxcomponent.h +++ b/ISV/include/isv_omxcomponent.h @@ -77,6 +77,8 @@ public: // return ISV component handle OMX_COMPONENTTYPE *getBaseComponent(){return &mBaseComponent;} + OMX_HANDLETYPE getComponent(){return static_cast<OMX_HANDLETYPE>(mComponent);} + static Vector<ISVComponent*> g_isv_components; private: /* diff --git a/ISV/omx/isv_omxcomponent.cpp b/ISV/omx/isv_omxcomponent.cpp index 1cce8a2..8be096e 100644 --- a/ISV/omx/isv_omxcomponent.cpp +++ b/ISV/omx/isv_omxcomponent.cpp @@ -24,10 +24,13 @@ #include <OMX_IndexExt.h> #include <hal_public.h> +#include "OMX_adaptor.h" + //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "isv-omxil" + using namespace android; /********************************************************************************** @@ -41,6 +44,8 @@ using namespace android; Vector<ISVComponent*> ISVComponent::g_isv_components; +extern MRM_OMX_Adaptor* g_mrm_omx_adaptor; + #ifndef TARGET_VPP_USE_GEN //global, static sp<ISVProcessor> ISVComponent::mProcThread = NULL; @@ -320,7 +325,15 @@ OMX_ERRORTYPE ISVComponent::ISV_SetParameter( return OMX_ErrorNone; } - OMX_ERRORTYPE err = OMX_SetParameter(mComponent, nIndex, pComponentParameterStructure); + // before setting param to real omx component, firstly set to media resource manager + OMX_ERRORTYPE err = g_mrm_omx_adaptor->MRM_OMX_SetParameter(mComponent, + nIndex, + pComponentParameterStructure); + if (err == OMX_ErrorInsufficientResources) { + return OMX_ErrorInsufficientResources; + } + + err = OMX_SetParameter(mComponent, nIndex, pComponentParameterStructure); if (err == OMX_ErrorNone && mVPPEnabled && mVPPOn) { if (nIndex == OMX_IndexParamPortDefinition) { OMX_PARAM_PORTDEFINITIONTYPE *def = diff --git a/ISV/omx/isv_omxcore.cpp b/ISV/omx/isv_omxcore.cpp index 4cd7238..bca96e7 100644 --- a/ISV/omx/isv_omxcore.cpp +++ b/ISV/omx/isv_omxcore.cpp @@ -25,6 +25,8 @@ #include "isv_omxcomponent.h" #include "isv_profile.h" +#include "OMX_adaptor.h" + //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "isv-omxil" @@ -48,6 +50,8 @@ static pthread_mutex_t g_module_lock = PTHREAD_MUTEX_INITIALIZER; static ISVOMXCore g_cores[CORE_NUMBER]; static Vector<ISVComponent*> g_isv_components; +MRM_OMX_Adaptor* g_mrm_omx_adaptor = NULL; + /********************************************************************************** * core entry */ @@ -104,6 +108,8 @@ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void) ALOGW("OMX IL core not found"); } } + g_mrm_omx_adaptor = MRM_OMX_Adaptor::getInstance(); + g_mrm_omx_adaptor->MRM_OMX_Init(); g_initialized = 1; } pthread_mutex_unlock(&g_module_lock); @@ -129,6 +135,10 @@ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void) } pthread_mutex_unlock(&g_module_lock); + if (g_mrm_omx_adaptor != NULL) { + g_mrm_omx_adaptor = NULL; + } + g_initialized = 0; ALOGD_IF(ISV_CORE_DEBUG, "%s: exit %d", __func__, ret); @@ -192,6 +202,14 @@ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle( return OMX_ErrorInsufficientResources; } + ret = g_mrm_omx_adaptor->MRM_OMX_CheckIfFullLoad(cComponentName); + if (ret == OMX_ErrorInsufficientResources) { + ALOGE("OMX_GetHandle failed. codec under full load status from media resource manager.\ + return OMX_ErrorInsufficientResources"); + pthread_mutex_unlock(&g_module_lock); + return OMX_ErrorInsufficientResources; + } + /* find the real component*/ for (OMX_U32 i = 0; i < CORE_NUMBER; i++) { if (g_cores[i].mLibHandle == NULL) { @@ -208,6 +226,10 @@ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle( *pHandle = pISVComponent->getBaseComponent(); ALOGD_IF(ISV_CORE_DEBUG, "%s: found component %s, pHandle %p", __func__, cComponentName, *pHandle); + + // set component into media resource manager adaptor + g_mrm_omx_adaptor->MRM_OMX_SetComponent(tempHandle, cComponentName); + pthread_mutex_unlock(&g_module_lock); return OMX_ErrorNone; } else if(omx_res == OMX_ErrorInsufficientResources) { @@ -245,6 +267,9 @@ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle( delete pComp; g_isv_components.removeAt(i); ALOGD_IF(ISV_CORE_DEBUG, "%s: free component %p success", __func__, hComponent); + + // remove it in media resource manager + g_mrm_omx_adaptor->MRM_OMX_RemoveComponent(pComp->getComponent()); pthread_mutex_unlock(&g_module_lock); return OMX_ErrorNone; } diff --git a/media_resource_manager/Android.mk b/media_resource_manager/Android.mk new file mode 100644 index 0000000..c577542 --- /dev/null +++ b/media_resource_manager/Android.mk @@ -0,0 +1,16 @@ + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_COPY_HEADERS_TO := media_resource_manager +LOCAL_COPY_HEADERS := \ + arbitrator/MediaResourceArbitrator.h \ + omx_adaptor/OMX_adaptor.h + +include $(BUILD_COPY_HEADERS) + +include $(CLEAR_VARS) +MEDIA_RESOURCE_MANAGER_ROOT := $(LOCAL_PATH) + +include $(CLEAR_VARS) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media_resource_manager/arbitrator/Android.mk b/media_resource_manager/arbitrator/Android.mk new file mode 100644 index 0000000..382f29f --- /dev/null +++ b/media_resource_manager/arbitrator/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + MediaResourceArbitrator.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils \ + libexpat \ + libdl \ + + +LOCAL_C_INCLUDES := \ + $(TARGET_OUT_HEADERS)/khronos/openmax \ + $(call include-path-for, frameworks-native)/media/openmax + + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := libmrm_arbitrator + +#LOCAL_CFLAGS += -Werror + +include $(BUILD_SHARED_LIBRARY) diff --git a/media_resource_manager/arbitrator/MediaResourceArbitrator.cpp b/media_resource_manager/arbitrator/MediaResourceArbitrator.cpp new file mode 100644 index 0000000..26be60b --- /dev/null +++ b/media_resource_manager/arbitrator/MediaResourceArbitrator.cpp @@ -0,0 +1,541 @@ +/* + * * Copyright (c) 2015 Intel Corporation. All rights reserved. + * * + * * 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 "MRM_Arbitrator" + +#include <libexpat/expat.h> +#include <string.h> +#include <stdio.h> +#include <utils/Log.h> +#include <unistd.h> +#include "MediaResourceArbitrator.h" + +using namespace android; + + +MediaResourceArbitrator::MediaResourceArbitrator() + : mIsEncoderUnderFullLoad (false), + mIsDecoderUnderFullLoad (false) { + ALOGV("construct MediaResourceArbitrator"); + pthread_mutex_init(&mArbitratorLock, NULL); + //InitializeCodecNameTypeMap(); + //InitializeResolutionNameTypeMap(); +} + + +MediaResourceArbitrator::~MediaResourceArbitrator() {} + + +ArbitratorErrorType MediaResourceArbitrator::Config(const char* configFilePath) { + FILE *fp = NULL; + + fp = ::fopen(configFilePath, "r"); + if (fp == NULL) { + ALOGV("%s: can not open config xml file.\ + try to set up default codec limitation"); + SetupDefaultCodecLimitation(); + return ArbitratorErrorNone; + } + + ParseXMLFile(fp); + return ArbitratorErrorNone; +} + + +bool MediaResourceArbitrator::CheckIfFullLoad(bool isEncoder) { + if (isEncoder) { + return mIsEncoderUnderFullLoad; + } else { + return mIsDecoderUnderFullLoad; + } +} + + +ArbitratorErrorType MediaResourceArbitrator::AddResource( + /* in */ CodecType codecType, + /* in */ bool isEncoder, + /* in */ bool isSecured, + /* in */ ResolutionType resolution, + /* in */ uint frameRate) { + ALOGV("MediaResourceArbitrator::AddResource ++"); + pthread_mutex_lock(&mArbitratorLock); + + ArbitratorErrorType err = ArbitratorErrorNone; + + if (CheckIfFullLoad(isEncoder) == true) { + pthread_mutex_unlock(&mArbitratorLock); + return ArbitratorErrorInsufficientResources; + } + + CodecInfo resource; + resource.codecType = codecType; + resource.isEncoder = isEncoder; + resource.isSecured = isSecured; + resource.resolution = resolution; + resource.frameRate = frameRate; + + ALOGV("Adding resource: codecType = %d, isEncoder = %d, isSecured = %d, resolution = %d, frameRate = %d", + codecType, isEncoder, isSecured, resolution, frameRate); + + if (isEncoder) { + mLivingEncodersTable.livingEncoders.push_back(resource); + if (resolution > mLivingEncodersTable.maxResolution) { + mLivingEncodersTable.maxResolution = resolution; + } + if (frameRate > mLivingEncodersTable.maxFrameRate) { + mLivingEncodersTable.maxFrameRate = frameRate; + } + } else { // decoder + mLivingDecodersTable.livingDecoders.push_back(resource); + if (resolution > mLivingDecodersTable.maxResolution) { + mLivingDecodersTable.maxResolution = resolution; + } + if (frameRate > mLivingDecodersTable.maxFrameRate) { + mLivingDecodersTable.maxFrameRate = frameRate; + } + } + + err = ArbitrateFullLoad(resource); + pthread_mutex_unlock(&mArbitratorLock); + + ALOGV("AddResource --"); + return err; +} + + +uint MediaResourceArbitrator::GetLivingCodecsNum(void) { + return mLivingDecodersTable.livingDecoders.size() + + mLivingEncodersTable.livingEncoders.size(); +} + + + +ArbitratorErrorType MediaResourceArbitrator::RemoveResource( + CodecType codecType, + bool isEncoder, + bool isSecured, + ResolutionType resolution, + uint frameRate) { + ALOGV("MediaResourceArbitrator::RemoveResource"); + + uint i; + ArbitratorErrorType err = ArbitratorErrorNone; + + pthread_mutex_lock(&mArbitratorLock); + + if (isEncoder) { + for(i=0; i<mLivingEncodersTable.livingEncoders.size(); i++) { + const CodecInfo& livingCodec = mLivingEncodersTable.livingEncoders[i]; + if ((livingCodec.codecType == codecType) && + (livingCodec.resolution == resolution) && + (livingCodec.frameRate == frameRate)) { + mLivingEncodersTable.livingEncoders.removeAt(i); + break; + } + } + mIsEncoderUnderFullLoad = false; + } else { + for(i=0; i<mLivingDecodersTable.livingDecoders.size(); i++) { + const CodecInfo& livingCodec = mLivingDecodersTable.livingDecoders[i]; + if ((livingCodec.codecType == codecType) && + (livingCodec.resolution == resolution) && + (livingCodec.isSecured == isSecured) && + (livingCodec.frameRate == frameRate)) { + mLivingDecodersTable.livingDecoders.removeAt(i); + break; + } + } + mIsDecoderUnderFullLoad = false; + } + pthread_mutex_unlock(&mArbitratorLock); + return err; +} + + +void MediaResourceArbitrator::ParseXMLFile(FILE* fp) { + ALOGV("MediaResourceArbitrator::ParseXMLFile"); + + int done; + void *pBuf = NULL; + + XML_Parser parser = ::XML_ParserCreate(NULL); + if (NULL == parser) { + ALOGE("@%s, line:%d, parser is NULL", __func__, __LINE__); + goto exit; + } + ::XML_SetUserData(parser, this); + ::XML_SetElementHandler(parser, startElement, endElement); + + pBuf = malloc(mBufSize); + if (NULL == pBuf) { + ALOGE("@%s, line:%d, failed to malloc buffer", __func__, __LINE__); + goto exit; + } + + do { + int len = (int)::fread(pBuf, 1, mBufSize, fp); + if (!len) { + if (ferror(fp)) { + clearerr(fp); + goto exit; + } + } + done = len < mBufSize; + if (XML_Parse(parser, (const char *)pBuf, len, done) == XML_STATUS_ERROR) { + ALOGE("@%s, line:%d, XML_Parse error", __func__, __LINE__); + goto exit; + } + } while (!done); + +exit: + if (parser) + ::XML_ParserFree(parser); + if (pBuf) + free(pBuf); + if (fp) + ::fclose(fp); + +} + + +ArbitratorErrorType MediaResourceArbitrator::ArbitrateFullLoad(CodecInfo& codec) { + ALOGV("MediaResourceArbitrator::ArbitrateFullLoad"); + ALOGV("giving codec type :%d, isEncoder = %d, frameRate = %d", + codec.codecType, codec.isEncoder, codec.frameRate); + ArbitratorErrorType err = ArbitratorErrorNone; + int livingInstanceNum = 0; + + if (codec.isEncoder == true) { + livingInstanceNum = mLivingEncodersTable.livingEncoders.size(); + } else { + livingInstanceNum = mLivingDecodersTable.livingDecoders.size(); + } + + ALOGV("current living codec number of %s is %d", + codec.isEncoder ? "encoder" : "decoder", livingInstanceNum); + + // check if living instance number reaches the limitation + int targetInstanceLimit = 5; // most optimistic + uint i,j; + + if (codec.isEncoder == false) { // decoder + for (i=0; i<mLivingDecodersTable.livingDecoders.size(); i++) { + const CodecInfo& livingCodec = mLivingDecodersTable.livingDecoders[i]; + for (j=0; j<mDecoderLimitInfos.size(); j++) { + const CodecInfo& targetCodec = mDecoderLimitInfos[j].codecInfo; + ALOGV("%dth codec in DecoderLimitInfos.",j); + if (CheckCodecMatched(livingCodec, targetCodec) == true) { + if (targetInstanceLimit > mDecoderLimitInfos[j].instanceLimit) { + targetInstanceLimit = mDecoderLimitInfos[j].instanceLimit; + break; + } + } + } + } + ALOGV("Go through decoder limit table and get current instance limit = %d", + targetInstanceLimit); + if (livingInstanceNum >= targetInstanceLimit) { + ALOGV("setting full load flag to true."); + mIsDecoderUnderFullLoad = true; + } else { + ALOGV("setting full load flag to false."); + mIsDecoderUnderFullLoad = false; + } + } else { // encoder + for(i=0; i<mLivingEncodersTable.livingEncoders.size(); i++) { + const CodecInfo& livingCodec = mLivingEncodersTable.livingEncoders[i]; + for (j=0; j<mEncoderLimitInfos.size(); j++) { + const CodecInfo& targetCodec = mEncoderLimitInfos[j].codecInfo; + if (CheckCodecMatched(livingCodec, targetCodec) == true) { + if (targetInstanceLimit > mEncoderLimitInfos[j].instanceLimit) { + targetInstanceLimit = mEncoderLimitInfos[j].instanceLimit; + break; + } + } + } + } + ALOGV("Go through encoder limit table and get current instance limit = %d", + targetInstanceLimit); + if (livingInstanceNum >= targetInstanceLimit) { + ALOGV("setting full load flag to true."); + mIsEncoderUnderFullLoad = true; + } else { + ALOGV("setting full load flag to false."); + mIsEncoderUnderFullLoad = false; + } + } + + return err; +} + + +bool MediaResourceArbitrator::CheckCodecMatched( + const CodecInfo& sourceCodec, + const CodecInfo& targetCodec) { + ALOGV("CheckCodecMatched"); + return ((sourceCodec.codecType == targetCodec.codecType) && + (sourceCodec.isSecured == targetCodec.isSecured) && + (sourceCodec.resolution == targetCodec.resolution) && + (sourceCodec.frameRate == targetCodec.frameRate)); +} + + +void MediaResourceArbitrator::DumpCodecTypeFromVector(void) { + unsigned int i; + ALOGV("MediaResourceArbitrator::DumpCodecTypeFromVector"); + for (i=0; i<mCodecNameTypeMap.size(); i++) { + ALOGV("codec type in vector %s : %d", + mCodecNameTypeMap.keyAt(i), mCodecNameTypeMap.valueAt(i)); + } +} + + +CodecType MediaResourceArbitrator::MapCodecTypeFromName(const char* name) { + if (strcmp(name, "CODEC_TYPE_AVC") == 0) { + return CODEC_TYPE_AVC; + } else if (strcmp(name, "CODEC_TYPE_HEVC") == 0) { + return CODEC_TYPE_HEVC; + } else if (strcmp(name, "CODEC_TYPE_VP8") == 0) { + return CODEC_TYPE_VP8; + } else if (strcmp(name, "CODEC_TYPE_VP9") == 0) { + return CODEC_TYPE_VP9; + } else if (strcmp(name, "CODEC_TYPE_MPEG2") == 0) { + return CODEC_TYPE_MPEG2; + } else if (strcmp(name, "CODEC_TYPE_MPEG4") == 0){ + return CODEC_TYPE_MPEG4; + } else if (strcmp(name, "CODEC_TYPE_H263") == 0) { + return CODEC_TYPE_H263; + } else if (strcmp(name, "CODEC_TYPE_WMV") == 0) { + return CODEC_TYPE_WMV; + } else if (strcmp(name, "CODEC_TYPE_VC1") == 0) { + return CODEC_TYPE_VC1; + } else { + ALOGE("unknown codec name: %s, try to return avc", name); + return CODEC_TYPE_AVC; + } +} + + +ResolutionType MediaResourceArbitrator:: + MapResolutionTypeFromName(const char* name) { + if (strcmp(name, "480") == 0) { + return Resolution_480; + } else if (strcmp(name, "720") == 0) { + return Resolution_720; + } else if (strcmp(name, "1080") == 0) { + return Resolution_1080; + } else if (strcmp(name, "2K") == 0) { + return Resolution_2K; + } else if (strcmp(name, "4K") == 0) { + return Resolution_4K; + } else { + ALOGE("unkown resolution name: %s, try to return 1080", name); + return Resolution_1080; + } +} + + +void MediaResourceArbitrator::InitializeCodecNameTypeMap(void) { + ALOGV("MediaResourceArbitrator::InitializeCodecNameTypeMap"); + mCodecNameTypeMap.add("CODEC_TYPE_AVC", CODEC_TYPE_AVC); + mCodecNameTypeMap.add("CODEC_TYPE_HEVC", CODEC_TYPE_HEVC); + mCodecNameTypeMap.add("CODEC_TYPE_VP8", CODEC_TYPE_VP8); + mCodecNameTypeMap.add("CODEC_TYPE_VP9", CODEC_TYPE_VP9); + mCodecNameTypeMap.add("CODEC_TYPE_MPEG4", CODEC_TYPE_MPEG4); + mCodecNameTypeMap.add("CODEC_TYPE_MPEG2", CODEC_TYPE_MPEG2); + mCodecNameTypeMap.add("CODEC_TYPE_H263", CODEC_TYPE_H263); + mCodecNameTypeMap.add("CODEC_TYPE_VC1", CODEC_TYPE_VC1); + mCodecNameTypeMap.add("CODEC_TYPE_WMV", CODEC_TYPE_WMV); + //DumpCodecTypeFromVector(); +} + + +void MediaResourceArbitrator::InitializeResolutionNameTypeMap(void) { + ALOGV("MediaResourceArbitrator::InitializeResolutionNameTypeMap"); + mResolutionNameTypeMap.add("480", Resolution_480); + mResolutionNameTypeMap.add("720", Resolution_720); + mResolutionNameTypeMap.add("1080", Resolution_1080); + mResolutionNameTypeMap.add("2K", Resolution_2K); + mResolutionNameTypeMap.add("4K", Resolution_4K); +} + +// Hard coded limitation +void MediaResourceArbitrator::SetupDefaultCodecLimitation(void) { + ALOGV("MediaResourceArbitrator::SetupDefaultCodecLimitation"); + uint i,j,k; + CodecType codecType; + ResolutionType resolutionType; + uint frameRate; + + // non-secure decoders + for (i=(int)CODEC_TYPE_AVC; i<(int)CODEC_TYPE_MAX; i++) { + codecType = (CodecType)i; + for (j=(int)Resolution_CIF; j<(int)Resolution_MAX; j++) { + resolutionType = (ResolutionType)j; + for (k=0; k<2; k++) { + frameRate = (k+1)*30; + bool isSecured = false; + CodecLimitInfo codecLimitInfo; + codecLimitInfo.codecInfo.codecType = codecType; + codecLimitInfo.codecInfo.resolution = resolutionType; + codecLimitInfo.codecInfo.isSecured = isSecured; + codecLimitInfo.codecInfo.isEncoder = false; + codecLimitInfo.codecInfo.frameRate = frameRate; + codecLimitInfo.instanceLimit = 2; + mDecoderLimitInfos.add(codecLimitInfo); + } + } + } + + // secure avc decoder + codecType = CODEC_TYPE_AVC; + for (j=(int)Resolution_CIF; j<(int)Resolution_MAX; j++) { + resolutionType = (ResolutionType)j; + for (k=0; k<2; k++) { + frameRate = (k+1)*30; + bool isSecured = true; + CodecLimitInfo codecLimitInfo; + codecLimitInfo.codecInfo.codecType = codecType; + codecLimitInfo.codecInfo.resolution = resolutionType; + codecLimitInfo.codecInfo.isSecured = isSecured; + codecLimitInfo.codecInfo.isEncoder = false; + codecLimitInfo.instanceLimit = 2; + mDecoderLimitInfos.add(codecLimitInfo); + } + } + + // Encoder limitation Map + for (i=(int)CODEC_TYPE_AVC; i<(int)CODEC_TYPE_MAX; i++) { + codecType = (CodecType)i; + for (j=(int)Resolution_CIF; j<(int)Resolution_MAX; j++) { + resolutionType = (ResolutionType)j; + for (k=0; k<2; k++) { + frameRate = (k+1)*30; + bool isSecured = false; + CodecLimitInfo codecLimitInfo; + codecLimitInfo.codecInfo.codecType = codecType; + codecLimitInfo.codecInfo.resolution = resolutionType; + codecLimitInfo.codecInfo.isSecured = isSecured; + codecLimitInfo.codecInfo.isEncoder = true; + codecLimitInfo.instanceLimit = 2; + mEncoderLimitInfos.add(codecLimitInfo); + } + } + } +} + + +void MediaResourceArbitrator::getConfigData(const char *name, + const char **atts) { + ALOGV("MediaResourceArbitrator::getConfigData"); + int attIndex = 0; + if (strcmp(name, "CodecResourcesLimitation") == 0) { + return; + } else if (strcmp(name, "Codec") == 0) { + if (strcmp(atts[attIndex], "name") == 0) { + ALOGV("Parsing codec %s", atts[attIndex+1]); + mIfParsingCodec = true; + } else { + ALOGE("Codec tag with no name, anything wrong?"); + } + } else if (strcmp(name, "codecType") == 0) { + ALOGV("parse tag codecType"); + if (mIfParsingCodec) { + if (strcmp(atts[attIndex], "value") == 0) { + //DumpCodecTypeFromVector(); + mParsingCodecLimitInfo.codecInfo.codecType = + MapCodecTypeFromName((const char*)atts[attIndex+1]); + } + } else { + ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name); + } + } else if (strcmp(name, "isEncoder") == 0) { + ALOGV("parse tag isEncoder"); + if (mIfParsingCodec && !strcmp(atts[attIndex], "value")) { + if (!strcmp(atts[attIndex + 1], "false")) + mParsingCodecLimitInfo.codecInfo.isEncoder = false; + else { + mParsingCodecLimitInfo.codecInfo.isEncoder = true; + } + } else { + ALOGE("Skip this element(%s) becaue this tag couldn't be supported\n", name); + } + } else if (strcmp(name, "isSecured") == 0) { + ALOGV("parse tag isSecured"); + if (mIfParsingCodec && !strcmp(atts[attIndex], "value")) { + if (!strcmp(atts[attIndex + 1], "false")) + mParsingCodecLimitInfo.codecInfo.isSecured = false; + else { + mParsingCodecLimitInfo.codecInfo.isSecured = true; + } + } else { + ALOGE("Skip this element(%s) becaue this tag couldn't be supported\n", name); + } + } else if (strcmp(name, "resolutionType") == 0) { + ALOGV("parse tag resolutionType"); + if (mIfParsingCodec) { + if (strcmp(atts[attIndex], "value") == 0) { + mParsingCodecLimitInfo.codecInfo.resolution = + MapResolutionTypeFromName((const char*)atts[attIndex+1]); + //mResolutionNameTypeMap.valueFor(atts[attIndex+1]); + } + } else { + ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name); + } + } else if (strcmp(name, "frameRate") == 0) { + ALOGV("parse tag frameRate"); + if (mIfParsingCodec) { + if (strcmp(atts[attIndex], "value") == 0) { + mParsingCodecLimitInfo.codecInfo.frameRate = atoi(atts[attIndex+1]); + } + } else { + ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name); + } + } else if (strcmp(name, "instanceLimit") == 0) { + ALOGV("parse tag instanceLimit"); + if (mIfParsingCodec) { + if (strcmp(atts[attIndex], "value") == 0) { + mParsingCodecLimitInfo.instanceLimit = atoi(atts[attIndex+1]); + } + } else { + ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name); + } + } +} + +// Start tag +void MediaResourceArbitrator::startElement(void *userData, + const char *name, + const char **atts) { + MediaResourceArbitrator* arbitrator = (MediaResourceArbitrator*)userData; + arbitrator->getConfigData(name, atts); +} + + +// End tag +void MediaResourceArbitrator::endElement(void *userData, const char *name) { + MediaResourceArbitrator* arbitrator = (MediaResourceArbitrator*)userData; + if (strcmp(name, "Codec") == 0) { + if (arbitrator->mParsingCodecLimitInfo.codecInfo.isEncoder == true) { + arbitrator->mEncoderLimitInfos.push_back(arbitrator->mParsingCodecLimitInfo); + } else { + arbitrator->mDecoderLimitInfos.push_back(arbitrator->mParsingCodecLimitInfo); + } + arbitrator->mIfParsingCodec = false; + } +} diff --git a/media_resource_manager/arbitrator/MediaResourceArbitrator.h b/media_resource_manager/arbitrator/MediaResourceArbitrator.h new file mode 100644 index 0000000..abb7b1a --- /dev/null +++ b/media_resource_manager/arbitrator/MediaResourceArbitrator.h @@ -0,0 +1,179 @@ +/* +* Copyright (c) 2015 Intel Corporation. All rights reserved. +* +* 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 MEDIA_RESOURCE_ARBITRATOR_H_ +#define MEDIA_RESOURCE_ARBITRATOR_H_ + +#include <unistd.h> +#include <string.h> +#include <utils/KeyedVector.h> +#include <utils/Vector.h> + +#define MAX_BUFFER_SIZE (20 * 1024) + +using namespace android; + +// This error type keeps align with the OMX error type +typedef enum _ArbitratorErrorType { + ArbitratorErrorNone = 0, + + /** There were insufficient resources to perform the requested operation */ + ArbitratorErrorInsufficientResources = 0x80001000, + + /** There was an error, but the cause of the error could not be determined */ + ArbitratorErrorUndefined = 0x80001001 +} ArbitratorErrorType; + + +typedef enum _ResolutionType { + Resolution_CIF = 0, + Resolution_480, + Resolution_720, + Resolution_1080, + Resolution_2K, + Resolution_4K, + Resolution_MAX +} ResolutionType; + + +typedef enum _CodecType { + CODEC_TYPE_AVC = 0, + CODEC_TYPE_HEVC, + CODEC_TYPE_VP8, + CODEC_TYPE_VP9, + CODEC_TYPE_MPEG4, + CODEC_TYPE_MPEG2, + CODEC_TYPE_H263, + CODEC_TYPE_VC1, + CODEC_TYPE_WMV, + CODEC_TYPE_MAX +} CodecType; + + +typedef struct _CodecInfo { + CodecType codecType; + bool isEncoder; + bool isSecured; + ResolutionType resolution; + uint frameRate; +} CodecInfo; + + +typedef struct _CodecLimitInfo { + CodecInfo codecInfo; + int instanceLimit; +} CodecLimitInfo; + + +typedef struct _LivingDecodersTable { + Vector<CodecInfo> livingDecoders; + uint maxResolution; + uint maxFrameRate; +} LivingDecodersTable; + + +typedef struct _LivingEncodersTable { + Vector<CodecInfo> livingEncoders; + uint maxResolution; + uint maxFrameRate; +} LivingEncodersTable; + + +class MediaResourceArbitrator { +public: + MediaResourceArbitrator (); + ~MediaResourceArbitrator (); + + /* Initialize the arbitrator. + Parse the config XML file if given. */ + ArbitratorErrorType Config(const char* configFilePath); + + /* Check if the resource limitation is hit and + it is under full load status. In such status, there + is no room to instantiate codec anymore. */ + bool CheckIfFullLoad(bool isEncoder); + + /* Add codec in the pool. + Resolution and frame rate must be provided. + This is not necessarily be called when codec instance + is constructed when the resolution and frame rate are + not known yet. + This may be called when codec is configured, + for example in OMX set parameter, etc. + Return value is expected to be as one of: + ArbitratorErrorNone, + ArbitratorErrorInsufficientResources + */ + ArbitratorErrorType AddResource(/* in */ CodecType codecType, + /* in */ bool isEncoder, + /* in */ bool isSecured, + /* in */ ResolutionType resolution, + /* in */ uint frameRate); + + /* Remove codec in the pool.*/ + ArbitratorErrorType RemoveResource(CodecType codecType, + bool isEncoder, + bool isSecured, + ResolutionType resolution, + uint frameRate); + + uint GetLivingCodecsNum(void); + + // XML function + void ParseXMLFile(FILE* fp); + static void startElement(void *userData, const char *name, const char **atts); + static void endElement(void *userData, const char *name); + void getConfigData(const char *name, const char **atts); + +private: + // a global table stores all codec limit info + Vector<CodecLimitInfo> mDecoderLimitInfos; + Vector<CodecLimitInfo> mEncoderLimitInfos; + + // a global talbe stores all living codec info + LivingDecodersTable mLivingDecodersTable; + LivingEncodersTable mLivingEncodersTable; + + // arbitrator lock + pthread_mutex_t mArbitratorLock; + + // indicate whether it is under full load status + bool mIsEncoderUnderFullLoad; + bool mIsDecoderUnderFullLoad; + + KeyedVector <const char*, CodecType> mCodecNameTypeMap; + KeyedVector <const char*, ResolutionType> mResolutionNameTypeMap; + + static const int mBufSize = MAX_BUFFER_SIZE; + // indicate XML parser is parsing a codec tag + bool mIfParsingCodec; + CodecLimitInfo mParsingCodecLimitInfo; + + ArbitratorErrorType ArbitrateFullLoad(CodecInfo& codec); + + bool CheckCodecMatched(const CodecInfo& sourceCodec, + const CodecInfo& targetCodec); + + void SetupDefaultCodecLimitation(void); + void InitializeCodecNameTypeMap(); + void InitializeResolutionNameTypeMap(); + void DumpCodecTypeFromVector(void); + CodecType MapCodecTypeFromName(const char* name); + ResolutionType MapResolutionTypeFromName(const char* name); +}; + +#endif /* MEDIA_RESOURCE_ARBITRATOR_H_ */ diff --git a/media_resource_manager/omx_adaptor/Android.mk b/media_resource_manager/omx_adaptor/Android.mk new file mode 100644 index 0000000..d30b8c1 --- /dev/null +++ b/media_resource_manager/omx_adaptor/Android.mk @@ -0,0 +1,26 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + OMX_adaptor.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils \ + libexpat \ + libdl \ + libmrm_arbitrator \ + + +LOCAL_C_INCLUDES := \ + $(TARGET_OUT_HEADERS)/khronos/openmax \ + $(call include-path-for, frameworks-native)/media/openmax \ + $(LOCAL_PATH)/../arbitrator \ + + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := libmrm_omx_adaptor + +#LOCAL_CFLAGS += -Werror + +include $(BUILD_SHARED_LIBRARY) diff --git a/media_resource_manager/omx_adaptor/OMX_adaptor.cpp b/media_resource_manager/omx_adaptor/OMX_adaptor.cpp new file mode 100644 index 0000000..2df886c --- /dev/null +++ b/media_resource_manager/omx_adaptor/OMX_adaptor.cpp @@ -0,0 +1,287 @@ +/* + * * Copyright (c) 2015 Intel Corporation. All rights reserved. + * * + * * 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 "MRM_OMX_Adaptor" + +#include <utils/Log.h> +#include <utils/threads.h> +#include "OMX_adaptor.h" + +const char* CODECS_LIMITATION_FILE = "/etc/codec_resources_limitation.xml"; + +using namespace android; + +// static member declare +MRM_OMX_Adaptor* MRM_OMX_Adaptor::sInstance = NULL; +Mutex MRM_OMX_Adaptor::sLock; + +typedef enum { + kPortIndexInput = 0, + kPortIndexOutput = 1 +} PORT_INDEX; + + +// case insensitive string finding +static const char* strstri(const char* str, const char* subStr) { + int len = strlen(subStr); + if (len == 0) { + return NULL; + } + + while(*str) { + if(strncasecmp(str, subStr, len) == 0) { + return str; + } + ++str; + } + return NULL; +} + + +//static +MRM_OMX_Adaptor* MRM_OMX_Adaptor::getInstance() { + ALOGV("getInstance()"); + Mutex::Autolock lock(sLock); + + if (sInstance == NULL) { + sInstance = new MRM_OMX_Adaptor(); + } + + return sInstance; +} + + +OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_Init(void) { + ALOGV("MRM_OMX_Init"); + OMX_ERRORTYPE err = OMX_ErrorNone; + if (mArbitrator != NULL) { + err = (OMX_ERRORTYPE)mArbitrator->Config(CODECS_LIMITATION_FILE); + } + return err; +} + + +OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_CheckIfFullLoad(OMX_STRING cComponentName) { + ALOGV("MRM_OMX_CheckIfFullLoad"); + Mutex::Autolock lock(sLock); + + String8 sComponentName(cComponentName); + AdaptorCodecInfo codecInfo; + ParseCodecInfoFromComponentName(sComponentName.string(), &codecInfo); + + if (codecInfo.isEncoder) { + ALOGV("Checking full load status of encoder."); + if (mArbitrator->CheckIfFullLoad(true/*encoder*/)) { + ALOGV("encoder in full load status. return OMX_ErrorInsufficientResources"); + return OMX_ErrorInsufficientResources; + } else { + return OMX_ErrorNone; + } + } else { + ALOGV("Checking full load status of decoder."); + if (mArbitrator->CheckIfFullLoad(false/*decoder*/)) { + ALOGV("decoder in full load status. return OMX_ErrorInsufficientResources"); + return OMX_ErrorInsufficientResources; + } else { + return OMX_ErrorNone; + } + } +} + + +void MRM_OMX_Adaptor::MRM_OMX_SetComponent( + OMX_HANDLETYPE pComponentHandle, + OMX_STRING cComponentName) { + ALOGV("MRM_OMX_SetComponent: %s", cComponentName); + String8 sComponentName(cComponentName); + ALOGV("pComponentHandle = 0x%x, componentName = %s", pComponentHandle, sComponentName.string()); + mComponentNameMap.add(pComponentHandle, sComponentName); +} + + +OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_SetParameter( + OMX_HANDLETYPE hComponent, + OMX_INDEXTYPE nIndex, + OMX_PTR pComponentParameterStructure) { + ALOGV("MRM_OMX_SetParameter"); + ALOGV("hComponent = 0x%x", hComponent); + OMX_ERRORTYPE err = OMX_ErrorNone; + + Mutex::Autolock lock(sLock); + + if (nIndex == OMX_IndexParamPortDefinition) { + OMX_PARAM_PORTDEFINITIONTYPE *def = + static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(pComponentParameterStructure); + + if (def->nPortIndex == kPortIndexInput) { + ALOGV("MRM_OMX_SetParameter for inport param def"); + if (mComponentFramerateMap.indexOfKey(hComponent) >= 0) { + ALOGV("setParameter is called again for component 0x%x inport", hComponent); + return OMX_ErrorNone; + } + + OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video; + uint frameRate = (uint)(video_def->xFramerate/65536); + ALOGV("frame rate from inport = %d", frameRate); + mComponentFramerateMap.add(hComponent, frameRate); + } + + if (def->nPortIndex == kPortIndexOutput) { + OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video; + + // if setParameter is not first called to this component's outport + // do not try to record its info for the second time + if (mComponentInfoMap.indexOfKey(hComponent) >= 0) { + ALOGV("setParameter is called again for component 0x%x outport", hComponent); + return OMX_ErrorNone; + } + + String8 sComponentName = mComponentNameMap.valueFor(hComponent); + ALOGV("component name from component map is %s", sComponentName.string()); + + AdaptorCodecInfo codecInfo; + ParseCodecInfoFromComponentName(sComponentName.string(), &codecInfo); + + if (mArbitrator->CheckIfFullLoad(codecInfo.isEncoder)) { + return OMX_ErrorInsufficientResources; + } + + ResolutionType resolution; + unsigned int height = video_def->nFrameHeight; + ALOGV("video resulotion = %d x %d", video_def->nFrameWidth, video_def->nFrameHeight); + if (height <= 480) { + resolution = Resolution_480; + } else if (height <= 720) { + resolution = Resolution_720; + } else if (height <= 1080) { + resolution = Resolution_1080; + } else if (height <= 1440) { + resolution = Resolution_2K; + } else if (height <= 2160) { + resolution = Resolution_4K; + } else { + ALOGE("resolution > 4K is not supported!"); + } + codecInfo.resolution = resolution; + + unsigned int frameRate = 0; + if (mComponentFramerateMap.indexOfKey(hComponent) >= 0) { + frameRate = mComponentFramerateMap.valueFor(hComponent); + } else { + ALOGW("frame rate was not set in inport def..."); + } + + ALOGV("frame rate from inport def = %d", frameRate); + if ((frameRate > 55) && (frameRate < 65)) { + frameRate = 60; + // This is a w/a to set default frame rate as 30 in case it is not + // set from framewrok. + } else { + frameRate = 30; + } + codecInfo.frameRate = frameRate; + err = (OMX_ERRORTYPE)mArbitrator->AddResource(codecInfo.codecType, + codecInfo.isEncoder, + codecInfo.isSecured, + codecInfo.resolution, + codecInfo.frameRate); + + mComponentInfoMap.add(hComponent, codecInfo); + } + } + return err; +} + + +OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_UseBuffer( + OMX_HANDLETYPE hComponent, + OMX_BUFFERHEADERTYPE **ppBufferHdr, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + OMX_U32 nSizeBytes, + OMX_U8 *pBuffer) { + ALOGV("MRM_OMX_UseBuffer"); + OMX_ERRORTYPE err = OMX_ErrorNone; + return err; +} + + +OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_RemoveComponent( + OMX_HANDLETYPE pComponentHandle) { + ALOGV("MRM_OMX_RemoveComponent"); + OMX_ERRORTYPE err = OMX_ErrorNone; + + if (mComponentInfoMap.indexOfKey(pComponentHandle) < 0) { + ALOGE("component 0x%x was not added by setParameter before! something is wrong?"); + return OMX_ErrorNone; // TODO: change to specific error. + } + + const AdaptorCodecInfo& codecInfo = mComponentInfoMap.valueFor(pComponentHandle); + + err = (OMX_ERRORTYPE)mArbitrator->RemoveResource(codecInfo.codecType, + codecInfo.isEncoder, + codecInfo.isSecured, + codecInfo.resolution, + codecInfo.frameRate); + return err; +} + + + + +void MRM_OMX_Adaptor::ParseCodecInfoFromComponentName( + const char* componentName, + AdaptorCodecInfo* codecInfo) { + ALOGV("ParseCodecInfoFromComponentName"); + ALOGV("componentName = %s", componentName); + bool isSecured = false; + if (strstri(componentName,"SECURE") != NULL) { + isSecured = true; + } + codecInfo->isSecured = isSecured; + + bool isEncoder = false; + if ((strstri(componentName, "ENCODER") != NULL) || + (strstri(componentName, "sw_ve") != NULL)) { + isEncoder = true; + } + codecInfo->isEncoder = isEncoder; + + CodecType codecType; + if (strstri(componentName, "AVC") != NULL) { + codecType = CODEC_TYPE_AVC; + } else if (strstri(componentName, "VP8") != NULL) { + codecType = CODEC_TYPE_VP8; + } else if (strstri(componentName, "VP9") != NULL) { + codecType = CODEC_TYPE_VP9; + } else if (strstri(componentName, "MPEG4") != NULL) { + codecType = CODEC_TYPE_MPEG4; + } else if (strstri(componentName, "MPEG2") != NULL) { + codecType = CODEC_TYPE_MPEG2; + } else if (strstri(componentName, "H263") != NULL) { + codecType = CODEC_TYPE_H263; + } else if (strstri(componentName, "H265") != NULL) { + codecType = CODEC_TYPE_HEVC; + } else if (strstri(componentName, "WMV") != NULL) { + codecType = CODEC_TYPE_WMV; + } + ALOGV("video codec type = %d", codecType); + codecInfo->codecType = codecType; +} + + diff --git a/media_resource_manager/omx_adaptor/OMX_adaptor.h b/media_resource_manager/omx_adaptor/OMX_adaptor.h new file mode 100644 index 0000000..145233d --- /dev/null +++ b/media_resource_manager/omx_adaptor/OMX_adaptor.h @@ -0,0 +1,117 @@ +/* +* Copyright (c) 2015 Intel Corporation. All rights reserved. +* +* 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 OMX_WRAPPER_H_ +#define OMX_WRAPPER_H_ + +#include <unistd.h> +#include <OMX_Core.h> +#include <OMX_Component.h> +#include <utils/threads.h> +#include <utils/KeyedVector.h> +#include <utils/String8.h> +#include "MediaResourceArbitrator.h" + +using namespace android; + +typedef KeyedVector <OMX_HANDLETYPE, String8> ComponentNameMap; +typedef KeyedVector <OMX_HANDLETYPE, uint> ComponentFramerateMap; + +typedef struct _AdaptorCodecInfo { + CodecType codecType; + bool isEncoder; + bool isSecured; + ResolutionType resolution; + uint frameRate; +} AdaptorCodecInfo; + +typedef KeyedVector <OMX_HANDLETYPE, AdaptorCodecInfo> ComponentInfoMap; + +class MRM_OMX_Adaptor { +public: + // Returns the singleton instance + static MRM_OMX_Adaptor* getInstance(); + + ~MRM_OMX_Adaptor() { + if (sInstance) { + delete sInstance; + sInstance = NULL; + } + }; + + // create and configure the MRM arbitrator + OMX_ERRORTYPE MRM_OMX_Init(void); + + + // check with MRM arbitrator if codec resource + // is under full load status. + // this should be called before OMX_GetHandle + // return OMX_ErrorInsufficientResources if true. + OMX_ERRORTYPE MRM_OMX_CheckIfFullLoad(OMX_STRING cComponentName); + + + // Set component name and component handle + // keeps this mapping but not adds resource yet. + // this intends to be called after OMX_GetHandle + void MRM_OMX_SetComponent( + OMX_HANDLETYPE pComponentHandle, + OMX_STRING cComponentName); + + + // handle the index 'OMX_IndexParamPortDefinition' + // when codec is configured, with resolution and + // frame rate. this actually adds resource + // to the MRM arbitrator. + // return OMX_ErrorInsufficientResources if failed. + OMX_ERRORTYPE MRM_OMX_SetParameter( + OMX_HANDLETYPE hComponent, + OMX_INDEXTYPE nIndex, + OMX_PTR pComponentParameterStructure); + + + // check grahpic buffer resource + // return OMX_ErrorInsufficientResources if under full load status. + OMX_ERRORTYPE MRM_OMX_UseBuffer( + OMX_HANDLETYPE hComponent, + OMX_BUFFERHEADERTYPE **ppBufferHdr, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + OMX_U32 nSizeBytes, + OMX_U8 *pBuffer); + + + // Remove the component + OMX_ERRORTYPE MRM_OMX_RemoveComponent(OMX_HANDLETYPE pComponentHandle); + +private: + MRM_OMX_Adaptor() { mArbitrator = new MediaResourceArbitrator(); } + MRM_OMX_Adaptor& operator=(const MRM_OMX_Adaptor&); // Don't call me + MRM_OMX_Adaptor(const MRM_OMX_Adaptor&); // Don't call me + + + void ParseCodecInfoFromComponentName(const char* componentName, + AdaptorCodecInfo* codecInfo); + + MediaResourceArbitrator* mArbitrator; + static Mutex sLock; + static MRM_OMX_Adaptor* sInstance; + + ComponentNameMap mComponentNameMap; + ComponentFramerateMap mComponentFramerateMap; + ComponentInfoMap mComponentInfoMap; +}; +#endif /* OMX_WRAPPER_H_ */ diff --git a/media_resource_manager/test/Android.mk b/media_resource_manager/test/Android.mk new file mode 100644 index 0000000..7703265 --- /dev/null +++ b/media_resource_manager/test/Android.mk @@ -0,0 +1,23 @@ +# Build the unit tests +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := MediaResourceManager_test + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := \ + MediaResourceManager_test.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libmrm_arbitrator \ + libutils \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../arbitrator \ + +#LOCAL_32_BIT_ONLY := true + +include $(BUILD_NATIVE_TEST) + diff --git a/media_resource_manager/test/MediaResourceManager_test.cpp b/media_resource_manager/test/MediaResourceManager_test.cpp new file mode 100644 index 0000000..4531d8c --- /dev/null +++ b/media_resource_manager/test/MediaResourceManager_test.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2015 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 "MediaResourceManager_test" +#include <utils/Log.h> + +#include <gtest/gtest.h> +#include "MediaResourceArbitrator.h" + +using namespace android; + + +class MediaResourceManagerTest : public ::testing::Test { +public: + MediaResourceManagerTest() + : mArbitrator(new MediaResourceArbitrator) { + mArbitrator->Config(NULL); + } + + ~MediaResourceManagerTest() { + delete mArbitrator; + } + +protected: + void addDefaultResourceByN(int N) { +/* + CodecInfo codec1; + codec1.codecType = CODEC_TYPE_AVC; + codec1.isEncoder = false; + codec1.isSecured = false; + codec1.resolution = Resolution_1080; + codec1.frameRate = 30; +*/ + int i; + ArbitratorErrorType err = ArbitratorErrorNone; + for (i=0; i<N; i++) { + err = mArbitrator->AddResource(CODEC_TYPE_AVC, + false, + false, + Resolution_1080, + 30); + if (err == ArbitratorErrorInsufficientResources) { + ALOGE("%dth codec can not be added anymore."); + return; + } + } + } + + void testAddResource(void) { + addDefaultResourceByN(10); + EXPECT_EQ(2u, mArbitrator->GetLivingCodecsNum()); + } + + + void testRemoveResource(void) { + addDefaultResourceByN(5); + EXPECT_EQ(2u, mArbitrator->GetLivingCodecsNum()); + EXPECT_TRUE(mArbitrator->CheckIfFullLoad(false)); + ArbitratorErrorType err = ArbitratorErrorNone; + err = mArbitrator->RemoveResource(CODEC_TYPE_AVC, + false, + false, + Resolution_1080, + 30); + EXPECT_EQ(1u, mArbitrator->GetLivingCodecsNum()); + EXPECT_FALSE(mArbitrator->CheckIfFullLoad(false)); + } + + + void testCheckFullLoad(void) { + EXPECT_FALSE(mArbitrator->CheckIfFullLoad(false)); + addDefaultResourceByN(5); + EXPECT_TRUE(mArbitrator->CheckIfFullLoad(false)); + } + + + void testConfigByXML(void) { + } + + + MediaResourceArbitrator* mArbitrator; +}; + + +TEST_F(MediaResourceManagerTest, config) { +} + + +TEST_F(MediaResourceManagerTest, addResource) { + testAddResource(); +} + + +TEST_F(MediaResourceManagerTest, removeResource) { + testRemoveResource(); +} + + +TEST_F(MediaResourceManagerTest, checkFullLoad) { + testCheckFullLoad(); +} + + +TEST_F(MediaResourceManagerTest, configByXML) { + testConfigByXML(); +} + + + |