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
useGoogleGoldfishComponentInstance(const char * libname)48 static bool useGoogleGoldfishComponentInstance(const char* libname) {
49 // We have a property set indicating whether to use the host side codec
50 // or not (ro.kernel.qemu.hwcodec.<mLibNameSuffix>).
51 char propValue[PROP_VALUE_MAX];
52 AString prop = "ro.kernel.qemu.hwcodec.";
53 prop.append(libname);
54
55 bool myret = property_get(prop.c_str(), propValue, "") > 0 &&
56 strcmp("1", propValue) == 0;
57 if (myret) {
58 ALOGD("%s %d found prop %s val %s", __func__, __LINE__, prop.c_str(), propValue);
59 }
60 return myret;
61 }
62
useAndroidGoldfishComponentInstance(const char * libname)63 static bool useAndroidGoldfishComponentInstance(const char* libname) {
64 // We have a property set indicating whether to use the host side codec
65 // or not (ro.kernel.qemu.hwcodec.<mLibNameSuffix>).
66 char propValue[PROP_VALUE_MAX];
67 AString prop = "ro.kernel.qemu.hwcodec.";
68 prop.append(libname);
69
70 bool myret = property_get(prop.c_str(), propValue, "") > 0 &&
71 strcmp("2", propValue) == 0;
72 if (myret) {
73 ALOGD("%s %d found prop %s val %s", __func__, __LINE__, prop.c_str(), propValue);
74 }
75 return myret;
76 }
77
78 static const GoldfishComponent kComponents[] = {
79 {"OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
80 {"OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
81 {"OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
82 {"OMX.android.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
83 {"OMX.android.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
84 {"OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
85 };
86
87 static std::vector<GoldfishComponent> kActiveComponents;
88
89 static const size_t kNumComponents =
90 sizeof(kComponents) / sizeof(kComponents[0]);
91
GoldfishOMXPlugin()92 GoldfishOMXPlugin::GoldfishOMXPlugin() {
93 for (int i = 0; i < kNumComponents; ++i) {
94 if ( !strncmp("OMX.google", kComponents[i].mName, 10) &&
95 useGoogleGoldfishComponentInstance(kComponents[i].mLibNameSuffix)) {
96 ALOGD("found and use kComponents[i].name %s", kComponents[i].mName);
97 kActiveComponents.push_back(kComponents[i]);
98 } else if (!strncmp("OMX.android", kComponents[i].mName, 11) &&
99 useAndroidGoldfishComponentInstance(kComponents[i].mLibNameSuffix)) {
100 ALOGD("found and use kComponents[i].name %s", kComponents[i].mName);
101 kActiveComponents.push_back(kComponents[i]);
102 }
103 }
104 }
105
makeComponentInstance(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)106 OMX_ERRORTYPE GoldfishOMXPlugin::makeComponentInstance(
107 const char *name,
108 const OMX_CALLBACKTYPE *callbacks,
109 OMX_PTR appData,
110 OMX_COMPONENTTYPE **component) {
111 ALOGI("makeComponentInstance '%s'", name);
112
113 for (size_t i = 0; i < kActiveComponents.size(); ++i) {
114 if (strcmp(name, kActiveComponents[i].mName)) {
115 continue;
116 }
117
118 AString libName;
119 AString ldsExport;
120 libName = "libstagefright_goldfish_";
121 ldsExport = "_Z26createGoldfishOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE";
122 ALOGI("Using goldfish codec for '%s'", kActiveComponents[i].mLibNameSuffix);
123
124 libName.append(kActiveComponents[i].mLibNameSuffix);
125 libName.append(".so");
126
127 void *libHandle = dlopen(libName.c_str(), RTLD_NOW|RTLD_NODELETE);
128
129 if (libHandle == NULL) {
130 ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror());
131
132 return OMX_ErrorComponentNotFound;
133 }
134
135 typedef GoldfishOMXComponent *(*CreateGoldfishOMXComponentFunc)(
136 const char *, const OMX_CALLBACKTYPE *,
137 OMX_PTR, OMX_COMPONENTTYPE **);
138
139 CreateGoldfishOMXComponentFunc createGoldfishOMXComponent =
140 (CreateGoldfishOMXComponentFunc)dlsym(
141 libHandle,
142 ldsExport.c_str()
143 );
144
145 if (createGoldfishOMXComponent == NULL) {
146 ALOGE("unable to create component for %s", libName.c_str());
147 dlclose(libHandle);
148 libHandle = NULL;
149
150 return OMX_ErrorComponentNotFound;
151 }
152
153 sp<GoldfishOMXComponent> codec =
154 (*createGoldfishOMXComponent)(name, callbacks, appData, component);
155
156 if (codec == NULL) {
157 dlclose(libHandle);
158 libHandle = NULL;
159
160 return OMX_ErrorInsufficientResources;
161 }
162
163 OMX_ERRORTYPE err = codec->initCheck();
164 if (err != OMX_ErrorNone) {
165 dlclose(libHandle);
166 libHandle = NULL;
167
168 return err;
169 }
170
171 codec->incStrong(this);
172 codec->setLibHandle(libHandle);
173
174 return OMX_ErrorNone;
175 }
176
177 return OMX_ErrorInvalidComponentName;
178 }
179
destroyComponentInstance(OMX_COMPONENTTYPE * component)180 OMX_ERRORTYPE GoldfishOMXPlugin::destroyComponentInstance(
181 OMX_COMPONENTTYPE *component) {
182 GoldfishOMXComponent *me =
183 (GoldfishOMXComponent *)
184 ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
185
186 me->prepareForDestruction();
187
188 CHECK_EQ(me->getStrongCount(), 1);
189 me->decStrong(this);
190 me = NULL;
191
192 return OMX_ErrorNone;
193 }
194
enumerateComponents(OMX_STRING name,size_t,OMX_U32 index)195 OMX_ERRORTYPE GoldfishOMXPlugin::enumerateComponents(
196 OMX_STRING name,
197 size_t /* size */,
198 OMX_U32 index) {
199 if (index >= kActiveComponents.size()) {
200 return OMX_ErrorNoMore;
201 }
202
203 ALOGD("enumerate %s component", kActiveComponents[index].mName);
204 strcpy(name, kActiveComponents[index].mName);
205
206 return OMX_ErrorNone;
207 }
208
getRolesOfComponent(const char * name,Vector<String8> * roles)209 OMX_ERRORTYPE GoldfishOMXPlugin::getRolesOfComponent(
210 const char *name,
211 Vector<String8> *roles) {
212 for (size_t i = 0; i < kActiveComponents.size(); ++i) {
213 if (strcmp(name, kActiveComponents[i].mName)) {
214 continue;
215 }
216
217 roles->clear();
218 roles->push(String8(kActiveComponents[i].mRole));
219
220 return OMX_ErrorNone;
221 }
222
223 return OMX_ErrorInvalidComponentName;
224 }
225
226 } // namespace android
227