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