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