1 /*
2  * * Copyright (c) 2015 Intel Corporation.  All rights reserved.
3  * *
4  * * Licensed under the Apache License, Version 2.0 (the "License");
5  * * you may not use this file except in compliance with the License.
6  * * You may obtain a copy of the License at
7  * *
8  * * http://www.apache.org/licenses/LICENSE-2.0
9  * *
10  * * Unless required by applicable law or agreed to in writing, software
11  * * distributed under the License is distributed on an "AS IS" BASIS,
12  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * * See the License for the specific language governing permissions and
14  * * limitations under the License.
15  * */
16 
17 
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "MRM_OMX_Adaptor"
20 
21 #include <utils/Log.h>
22 #include <utils/threads.h>
23 #include "OMX_adaptor.h"
24 
25 const char* CODECS_LIMITATION_FILE = "/etc/codec_resources_limitation.xml";
26 
27 using namespace android;
28 
29 // static member declare
30 MRM_OMX_Adaptor* MRM_OMX_Adaptor::sInstance = NULL;
31 Mutex MRM_OMX_Adaptor::sLock;
32 
33 typedef enum {
34     kPortIndexInput  = 0,
35     kPortIndexOutput = 1
36 } PORT_INDEX;
37 
38 
39 // case insensitive string finding
strstri(const char * str,const char * subStr)40 static const char* strstri(const char* str, const char* subStr) {
41     int len = strlen(subStr);
42     if (len == 0) {
43         return NULL;
44     }
45 
46     while(*str) {
47         if(strncasecmp(str, subStr, len) == 0) {
48             return str;
49         }
50         ++str;
51     }
52     return NULL;
53 }
54 
55 
56 //static
getInstance()57 MRM_OMX_Adaptor* MRM_OMX_Adaptor::getInstance() {
58     ALOGV("getInstance()");
59     Mutex::Autolock lock(sLock);
60 
61     if (sInstance == NULL) {
62         sInstance = new MRM_OMX_Adaptor();
63     }
64 
65     return sInstance;
66 }
67 
68 
MRM_OMX_Init(void)69 OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_Init(void) {
70     ALOGV("MRM_OMX_Init");
71     OMX_ERRORTYPE err = OMX_ErrorNone;
72     if (mArbitrator != NULL) {
73         err = (OMX_ERRORTYPE)mArbitrator->Config(CODECS_LIMITATION_FILE);
74     }
75     return err;
76 }
77 
78 
MRM_OMX_CheckIfFullLoad(OMX_STRING cComponentName)79 OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_CheckIfFullLoad(OMX_STRING cComponentName) {
80     ALOGV("MRM_OMX_CheckIfFullLoad");
81     Mutex::Autolock lock(sLock);
82 
83     String8 sComponentName(cComponentName);
84     AdaptorCodecInfo codecInfo;
85     ParseCodecInfoFromComponentName(sComponentName.string(), &codecInfo);
86 
87     if (codecInfo.isEncoder) {
88         ALOGV("Checking full load status of encoder.");
89         if (mArbitrator->CheckIfFullLoad(true/*encoder*/)) {
90             ALOGV("encoder in full load status. return OMX_ErrorInsufficientResources");
91             return OMX_ErrorInsufficientResources;
92         } else {
93             return OMX_ErrorNone;
94         }
95     } else {
96         ALOGV("Checking full load status of decoder.");
97         if (mArbitrator->CheckIfFullLoad(false/*decoder*/)) {
98             ALOGV("decoder in full load status. return OMX_ErrorInsufficientResources");
99             return OMX_ErrorInsufficientResources;
100         } else {
101             return OMX_ErrorNone;
102         }
103     }
104 }
105 
106 
MRM_OMX_SetComponent(OMX_HANDLETYPE pComponentHandle,OMX_STRING cComponentName)107 void MRM_OMX_Adaptor::MRM_OMX_SetComponent(
108                           OMX_HANDLETYPE pComponentHandle,
109                           OMX_STRING cComponentName) {
110     ALOGV("MRM_OMX_SetComponent: %s", cComponentName);
111     String8 sComponentName(cComponentName);
112     ALOGV("pComponentHandle = 0x%x, componentName = %s", pComponentHandle, sComponentName.string());
113     mComponentNameMap.add(pComponentHandle, sComponentName);
114 }
115 
116 
MRM_OMX_SetParameter(OMX_HANDLETYPE hComponent,OMX_INDEXTYPE nIndex,OMX_PTR pComponentParameterStructure)117 OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_SetParameter(
118                          OMX_HANDLETYPE hComponent,
119                          OMX_INDEXTYPE nIndex,
120                          OMX_PTR pComponentParameterStructure) {
121     ALOGV("MRM_OMX_SetParameter");
122     ALOGV("hComponent = 0x%x", hComponent);
123     OMX_ERRORTYPE err = OMX_ErrorNone;
124 
125     Mutex::Autolock lock(sLock);
126 
127     if (nIndex == OMX_IndexParamPortDefinition) {
128         OMX_PARAM_PORTDEFINITIONTYPE *def =
129             static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(pComponentParameterStructure);
130 
131         if (def->nPortIndex == kPortIndexInput) {
132             ALOGV("MRM_OMX_SetParameter for inport param def");
133             if (mComponentFramerateMap.indexOfKey(hComponent) >= 0) {
134                 ALOGV("setParameter is called again for component 0x%x inport", hComponent);
135                 return OMX_ErrorNone;
136             }
137 
138             OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video;
139             uint frameRate = (uint)(video_def->xFramerate/65536);
140             ALOGV("frame rate from inport = %d", frameRate);
141             mComponentFramerateMap.add(hComponent, frameRate);
142         }
143 
144         if (def->nPortIndex == kPortIndexOutput) {
145             OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video;
146 
147             // if setParameter is not first called to this component's outport
148             // do not try to record its info for the second time
149             if (mComponentInfoMap.indexOfKey(hComponent) >= 0) {
150                 ALOGV("setParameter is called again for component 0x%x outport", hComponent);
151                 return OMX_ErrorNone;
152             }
153 
154             String8 sComponentName = mComponentNameMap.valueFor(hComponent);
155             ALOGV("component name from component map is %s", sComponentName.string());
156 
157             AdaptorCodecInfo codecInfo;
158             ParseCodecInfoFromComponentName(sComponentName.string(), &codecInfo);
159 
160             if (mArbitrator->CheckIfFullLoad(codecInfo.isEncoder)) {
161                 return OMX_ErrorInsufficientResources;
162             }
163 
164             ResolutionType resolution;
165             unsigned int height = video_def->nFrameHeight;
166             ALOGV("video resulotion = %d x %d", video_def->nFrameWidth, video_def->nFrameHeight);
167             if (height <= 480) {
168                 resolution = Resolution_480;
169             } else if (height <= 720) {
170                 resolution = Resolution_720;
171             } else if (height <= 1080) {
172                 resolution = Resolution_1080;
173             } else if (height <= 1440) {
174                 resolution = Resolution_2K;
175             } else if (height <= 2160) {
176                 resolution = Resolution_4K;
177             } else {
178                 ALOGE("resolution > 4K is not supported!");
179             }
180             codecInfo.resolution = resolution;
181 
182             unsigned int frameRate = 0;
183             if (mComponentFramerateMap.indexOfKey(hComponent) >= 0) {
184                 frameRate = mComponentFramerateMap.valueFor(hComponent);
185             } else {
186                 ALOGW("frame rate was not set in inport def...");
187             }
188 
189             ALOGV("frame rate from inport def = %d", frameRate);
190             if ((frameRate > 55) && (frameRate < 65)) {
191                 frameRate = 60;
192             // This is a w/a to set default frame rate as 30 in case it is not
193             // set from framewrok.
194             } else {
195                 frameRate = 30;
196             }
197             codecInfo.frameRate = frameRate;
198             err = (OMX_ERRORTYPE)mArbitrator->AddResource(codecInfo.codecType,
199                                                           codecInfo.isEncoder,
200                                                           codecInfo.isSecured,
201                                                           codecInfo.resolution,
202                                                           codecInfo.frameRate);
203 
204             mComponentInfoMap.add(hComponent, codecInfo);
205         }
206     }
207     return err;
208 }
209 
210 
MRM_OMX_UseBuffer(OMX_HANDLETYPE hComponent,OMX_BUFFERHEADERTYPE ** ppBufferHdr,OMX_U32 nPortIndex,OMX_PTR pAppPrivate,OMX_U32 nSizeBytes,OMX_U8 * pBuffer)211 OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_UseBuffer(
212                          OMX_HANDLETYPE hComponent,
213                          OMX_BUFFERHEADERTYPE **ppBufferHdr,
214                          OMX_U32 nPortIndex,
215                          OMX_PTR pAppPrivate,
216                          OMX_U32 nSizeBytes,
217                          OMX_U8 *pBuffer) {
218     ALOGV("MRM_OMX_UseBuffer");
219     OMX_ERRORTYPE err = OMX_ErrorNone;
220     return err;
221 }
222 
223 
MRM_OMX_RemoveComponent(OMX_HANDLETYPE pComponentHandle)224 OMX_ERRORTYPE MRM_OMX_Adaptor::MRM_OMX_RemoveComponent(
225                                    OMX_HANDLETYPE pComponentHandle) {
226     ALOGV("MRM_OMX_RemoveComponent 0x%x", pComponentHandle);
227     OMX_ERRORTYPE err = OMX_ErrorNone;
228 
229     if (mComponentInfoMap.indexOfKey(pComponentHandle) < 0) {
230         ALOGE("component 0x%x was not added by setParameter before! something is wrong?",pComponentHandle);
231         return OMX_ErrorNone; // TODO: change to specific error.
232     }
233 
234     const AdaptorCodecInfo& codecInfo = mComponentInfoMap.valueFor(pComponentHandle);
235 
236     err = (OMX_ERRORTYPE)mArbitrator->RemoveResource(codecInfo.codecType,
237                                                   codecInfo.isEncoder,
238                                                   codecInfo.isSecured,
239                                                   codecInfo.resolution,
240                                                   codecInfo.frameRate);
241     mComponentInfoMap.removeItem(pComponentHandle);
242     return err;
243 }
244 
245 
246 
247 
ParseCodecInfoFromComponentName(const char * componentName,AdaptorCodecInfo * codecInfo)248 void MRM_OMX_Adaptor::ParseCodecInfoFromComponentName(
249                                          const char* componentName,
250                                          AdaptorCodecInfo* codecInfo) {
251     ALOGV("ParseCodecInfoFromComponentName");
252     ALOGV("componentName = %s", componentName);
253     bool isSecured = false;
254     if (strstri(componentName,"SECURE") != NULL) {
255         isSecured = true;
256     }
257     codecInfo->isSecured = isSecured;
258 
259     bool isEncoder = false;
260     if ((strstri(componentName, "ENCODER") != NULL) ||
261         (strstri(componentName, "sw_ve") != NULL)) {
262         isEncoder = true;
263     }
264     codecInfo->isEncoder = isEncoder;
265 
266     CodecType codecType = CODEC_TYPE_MAX;
267     if (strstri(componentName, "AVC") != NULL) {
268         codecType = CODEC_TYPE_AVC;
269     } else if (strstri(componentName, "VP8") != NULL) {
270         codecType = CODEC_TYPE_VP8;
271     } else if (strstri(componentName, "VP9") != NULL) {
272         codecType = CODEC_TYPE_VP9;
273     } else if (strstri(componentName, "MPEG4") != NULL) {
274         codecType = CODEC_TYPE_MPEG4;
275     } else if (strstri(componentName, "MPEG2") != NULL) {
276         codecType = CODEC_TYPE_MPEG2;
277     } else if (strstri(componentName, "H263") != NULL) {
278         codecType = CODEC_TYPE_H263;
279     } else if (strstri(componentName, "H265") != NULL) {
280         codecType = CODEC_TYPE_HEVC;
281     } else if (strstri(componentName, "WMV") != NULL) {
282         codecType = CODEC_TYPE_WMV;
283     }
284     ALOGV("video codec type = %d", codecType);
285     codecInfo->codecType = codecType;
286 }
287 
288 
289