1 /*
2  * Copyright 2018 The Android Open Source Project
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 #define LOG_TAG "GoldfishOMXPlugin"
18 #include "GoldfishOMXPlugin.h"
19 
20 //#define LOG_NDEBUG 0
21 #include <vector>
22 
23 #include <cutils/properties.h>
24 #include <log/log.h>
25 
26 #include "GoldfishOMXComponent.h"
27 
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <media/stagefright/foundation/AString.h>
30 
31 #include <dlfcn.h>
32 
33 namespace android {
34 
createOMXPlugin()35 OMXPluginBase *createOMXPlugin() {
36     ALOGD("called createOMXPlugin for Goldfish");
37     return new GoldfishOMXPlugin;
38 }
39 
40 // Each component's name should have it's own feature flag in order to toggle
41 // individual codecs
42 struct GoldfishComponent {
43     const char *mName;
44     const char *mLibNameSuffix;
45     const char *mRole;
46 };
47 
useOmxCodecs()48 static bool useOmxCodecs() {
49     char propValue[PROP_VALUE_MAX];
50     AString prop = "debug.stagefright.ccodec";
51     bool myret = property_get(prop.c_str(), propValue, "") > 0 &&
52            strcmp("0", propValue) == 0;
53     if (myret) {
54         ALOGD("%s %d found prop %s val %s", __func__, __LINE__, prop.c_str(), propValue);
55     }
56     return myret;
57 }
58 
59 // We have a property set indicating whether to use the host side codec
60 // or not (ro.boot.qemu.hwcodec.<mLibNameSuffix>).
BuildHWCodecPropName(const char * libname)61 static std::string BuildHWCodecPropName(const char *libname) {
62     using namespace std::literals::string_literals;
63     return "ro.boot.qemu.hwcodec."s + libname;
64 }
65 
useGoogleGoldfishComponentInstance(const char * libname)66 static bool useGoogleGoldfishComponentInstance(const char* libname) {
67     const std::string propName = BuildHWCodecPropName(libname);
68     char propValue[PROP_VALUE_MAX];
69 
70     bool myret = property_get(propName.c_str(), propValue, "") > 0 &&
71            strcmp("1", propValue) == 0;
72     if (myret) {
73         ALOGD("%s %d found prop %s val %s", __func__, __LINE__, propName.c_str(), propValue);
74     }
75     return myret;
76 }
77 
useAndroidGoldfishComponentInstance(const char * libname)78 static bool useAndroidGoldfishComponentInstance(const char* libname) {
79     const std::string propName = BuildHWCodecPropName(libname);
80     char propValue[PROP_VALUE_MAX];
81 
82     bool myret = property_get(propName.c_str(), propValue, "") > 0 &&
83            strcmp("2", propValue) == 0;
84     if (myret) {
85         ALOGD("%s %d found prop %s val %s", __func__, __LINE__, propName.c_str(), propValue);
86     }
87     return myret;
88 }
89 
90 static const GoldfishComponent kComponents[] = {
91         {"OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
92         {"OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
93         {"OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
94         {"OMX.android.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
95         {"OMX.android.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
96         {"OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
97 };
98 
99 static std::vector<GoldfishComponent> kActiveComponents;
100 
101 static const size_t kNumComponents =
102     sizeof(kComponents) / sizeof(kComponents[0]);
103 
GoldfishOMXPlugin()104 GoldfishOMXPlugin::GoldfishOMXPlugin() {
105     if (useOmxCodecs()) {
106         for (int i = 0; i < kNumComponents; ++i) {
107             if (!strncmp("OMX.google", kComponents[i].mName, 10) &&
108                 useGoogleGoldfishComponentInstance(
109                     kComponents[i].mLibNameSuffix)) {
110                 ALOGD("found and use kComponents[i].name %s",
111                       kComponents[i].mName);
112                 kActiveComponents.push_back(kComponents[i]);
113             } else if (!strncmp("OMX.android", kComponents[i].mName, 11) &&
114                        useAndroidGoldfishComponentInstance(
115                            kComponents[i].mLibNameSuffix)) {
116                 ALOGD("found and use kComponents[i].name %s",
117                       kComponents[i].mName);
118                 kActiveComponents.push_back(kComponents[i]);
119             }
120         }
121     }
122 }
123 
makeComponentInstance(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)124 OMX_ERRORTYPE GoldfishOMXPlugin::makeComponentInstance(
125         const char *name,
126         const OMX_CALLBACKTYPE *callbacks,
127         OMX_PTR appData,
128         OMX_COMPONENTTYPE **component) {
129     ALOGI("makeComponentInstance '%s'", name);
130 
131     for (size_t i = 0; i < kActiveComponents.size(); ++i) {
132         if (strcmp(name, kActiveComponents[i].mName)) {
133             continue;
134         }
135 
136         AString libName;
137         AString ldsExport;
138         libName = "libstagefright_goldfish_";
139         ldsExport = "_Z26createGoldfishOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE";
140         ALOGI("Using goldfish codec for '%s'", kActiveComponents[i].mLibNameSuffix);
141 
142         libName.append(kActiveComponents[i].mLibNameSuffix);
143         libName.append(".so");
144 
145         void *libHandle = dlopen(libName.c_str(), RTLD_NOW|RTLD_NODELETE);
146 
147         if (libHandle == NULL) {
148             ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror());
149 
150             return OMX_ErrorComponentNotFound;
151         }
152 
153         typedef GoldfishOMXComponent *(*CreateGoldfishOMXComponentFunc)(
154                 const char *, const OMX_CALLBACKTYPE *,
155                 OMX_PTR, OMX_COMPONENTTYPE **);
156 
157         CreateGoldfishOMXComponentFunc createGoldfishOMXComponent =
158             (CreateGoldfishOMXComponentFunc)dlsym(
159                     libHandle,
160                     ldsExport.c_str()
161                     );
162 
163         if (createGoldfishOMXComponent == NULL) {
164             ALOGE("unable to create component for %s", libName.c_str());
165             dlclose(libHandle);
166             libHandle = NULL;
167 
168             return OMX_ErrorComponentNotFound;
169         }
170 
171         sp<GoldfishOMXComponent> codec =
172             (*createGoldfishOMXComponent)(name, callbacks, appData, component);
173 
174         if (codec == NULL) {
175             dlclose(libHandle);
176             libHandle = NULL;
177 
178             return OMX_ErrorInsufficientResources;
179         }
180 
181         OMX_ERRORTYPE err = codec->initCheck();
182         if (err != OMX_ErrorNone) {
183             dlclose(libHandle);
184             libHandle = NULL;
185 
186             return err;
187         }
188 
189         codec->incStrong(this);
190         codec->setLibHandle(libHandle);
191 
192         return OMX_ErrorNone;
193     }
194 
195     return OMX_ErrorInvalidComponentName;
196 }
197 
destroyComponentInstance(OMX_COMPONENTTYPE * component)198 OMX_ERRORTYPE GoldfishOMXPlugin::destroyComponentInstance(
199         OMX_COMPONENTTYPE *component) {
200     GoldfishOMXComponent *me =
201         (GoldfishOMXComponent *)
202             ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
203 
204     me->prepareForDestruction();
205 
206     CHECK_EQ(me->getStrongCount(), 1);
207     me->decStrong(this);
208     me = NULL;
209 
210     return OMX_ErrorNone;
211 }
212 
enumerateComponents(OMX_STRING name,size_t,OMX_U32 index)213 OMX_ERRORTYPE GoldfishOMXPlugin::enumerateComponents(
214         OMX_STRING name,
215         size_t /* size */,
216         OMX_U32 index) {
217     if (index >= kActiveComponents.size()) {
218         return OMX_ErrorNoMore;
219     }
220 
221     ALOGD("enumerate %s component", kActiveComponents[index].mName);
222     strcpy(name, kActiveComponents[index].mName);
223 
224     return OMX_ErrorNone;
225 }
226 
getRolesOfComponent(const char * name,Vector<String8> * roles)227 OMX_ERRORTYPE GoldfishOMXPlugin::getRolesOfComponent(
228         const char *name,
229         Vector<String8> *roles) {
230     for (size_t i = 0; i < kActiveComponents.size(); ++i) {
231         if (strcmp(name, kActiveComponents[i].mName)) {
232             continue;
233         }
234 
235         roles->clear();
236         roles->push(String8(kActiveComponents[i].mRole));
237 
238         return OMX_ErrorNone;
239     }
240 
241     return OMX_ErrorInvalidComponentName;
242 }
243 
244 }  // namespace android
245