1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "engine_factory_repo.h"
17 #include <limits>
18 #include <cinttypes>
19 #include <dlfcn.h>
20 #include "directory_ex.h"
21 #include "media_errors.h"
22 #include "media_log.h"
23 #include "parameter.h"
24
25 namespace {
26 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "EngineFactoryRepo"};
27 #ifdef __aarch64__
28 static const std::string MEDIA_ENGINE_LIB_PATH = "/system/lib64/media";
29 #else
30 static const std::string MEDIA_ENGINE_LIB_PATH = "/system/lib/media";
31 #endif
32 static const std::string MEDIA_ENGINE_LIB_NAME_GSTREAMER = "libmedia_engine_gst.z.so";
33 static const std::string MEDIA_ENGINE_LIB_NAME_HISTREAMER = "libmedia_engine_histreamer.z.so";
34 static const std::string MEDIA_ENGINE_ENTRY_SYMBOL = "CreateEngineFactory";
35 }
36
37 namespace OHOS {
38 namespace Media {
39 using CreateFactoryFunc = IEngineFactory *(*)();
40
Instance()41 EngineFactoryRepo &EngineFactoryRepo::Instance()
42 {
43 static EngineFactoryRepo inst;
44 return inst;
45 }
46
~EngineFactoryRepo()47 EngineFactoryRepo::~EngineFactoryRepo()
48 {
49 factorys_.clear();
50 for (auto &lib : factoryLibs_) {
51 if (lib != nullptr) {
52 (void)dlclose(lib);
53 lib = nullptr;
54 }
55 }
56 }
57
LoadLib(const std::string & libPath)58 int32_t __attribute__((no_sanitize("cfi"))) EngineFactoryRepo::LoadLib(const std::string &libPath)
59 {
60 void *handle = dlopen(libPath.c_str(), RTLD_NOW | RTLD_LOCAL);
61 if (handle == nullptr) {
62 MEDIA_LOGE("failed to dlopen %{public}s, errno:%{public}d, errormsg:%{public}s",
63 libPath.c_str(), errno, dlerror());
64 return MSERR_OPEN_FILE_FAILED;
65 }
66
67 CreateFactoryFunc entry = reinterpret_cast<CreateFactoryFunc>(dlsym(handle, MEDIA_ENGINE_ENTRY_SYMBOL.c_str()));
68 if (entry == nullptr) {
69 MEDIA_LOGE("failed to dlsym %{public}s for lib %{public}s, errno:%{public}d, errormsg:%{public}s",
70 MEDIA_ENGINE_ENTRY_SYMBOL.c_str(), libPath.c_str(), errno, dlerror());
71 (void)dlclose(handle);
72 return MSERR_OPEN_FILE_FAILED;
73 }
74
75 std::shared_ptr<IEngineFactory> factory = std::shared_ptr<IEngineFactory>(entry());
76 if (factory == nullptr) {
77 MEDIA_LOGE("failed to create engine factory for lib: %{public}s", libPath.c_str());
78 (void)dlclose(handle);
79 return MSERR_OPEN_FILE_FAILED;
80 }
81
82 factoryLibs_.push_back(handle);
83 factorys_.push_back(factory);
84 return MSERR_OK;
85 }
86
LoadGstreamerEngine()87 int32_t EngineFactoryRepo::LoadGstreamerEngine()
88 {
89 std::unique_lock<std::mutex> lock(mutex_);
90 if (isLoadGstreamer_) {
91 return MSERR_OK;
92 }
93
94 std::vector<std::string> allFiles;
95 GetDirFiles(MEDIA_ENGINE_LIB_PATH, allFiles);
96 for (auto &file : allFiles) {
97 std::string::size_type namePos = file.find(MEDIA_ENGINE_LIB_NAME_GSTREAMER);
98 if (namePos == std::string::npos) {
99 continue;
100 } else {
101 CHECK_AND_RETURN_RET_LOG(LoadLib(file) == MSERR_OK, MSERR_OPEN_FILE_FAILED, "LoadLib failed");
102 isLoadGstreamer_ = true;
103 break;
104 }
105 }
106
107 return MSERR_OK;
108 }
109
LoadHistreamerEngine()110 int32_t EngineFactoryRepo::LoadHistreamerEngine()
111 {
112 std::unique_lock<std::mutex> lock(mutex_);
113 if (isLoadHistreamer_) {
114 MEDIA_LOGI("Histreamer is enabled");
115 return MSERR_OK;
116 }
117
118 char useHistreamer[10] = {0}; // 10 for system parameter usage
119 auto res = GetParameter("debug.media_service.histreamer", "0", useHistreamer, sizeof(useHistreamer));
120 if (res == 1 && useHistreamer[0] == '1') {
121 std::vector<std::string> allFiles;
122 GetDirFiles(MEDIA_ENGINE_LIB_PATH, allFiles);
123 for (auto &file : allFiles) {
124 std::string::size_type namePos = file.find(MEDIA_ENGINE_LIB_NAME_HISTREAMER);
125 if (namePos == std::string::npos) {
126 continue;
127 } else {
128 CHECK_AND_RETURN_RET_LOG(LoadLib(file) == MSERR_OK, MSERR_OPEN_FILE_FAILED, "LoadLib failed");
129 isLoadHistreamer_ = true;
130 break;
131 }
132 }
133 }
134
135 return MSERR_OK;
136 }
137
GetEngineFactory(IEngineFactory::Scene scene,const std::string & uri)138 std::shared_ptr<IEngineFactory> EngineFactoryRepo::GetEngineFactory(
139 IEngineFactory::Scene scene, const std::string &uri)
140 {
141 (void)LoadGstreamerEngine();
142 (void)LoadHistreamerEngine();
143
144 if (factorys_.empty()) {
145 isLoadGstreamer_ = false;
146 isLoadHistreamer_ = false;
147 MEDIA_LOGE("Failed to load media engine library");
148 return nullptr;
149 }
150
151 int32_t maxScore = std::numeric_limits<int32_t>::min();
152 std::shared_ptr<IEngineFactory> target = nullptr;
153 for (auto &factory : factorys_) {
154 int32_t score = factory->Score(scene, uri);
155 if (maxScore < score) {
156 maxScore = score;
157 target = factory;
158 }
159 }
160 if (target == nullptr && !factorys_.empty()) {
161 target = factorys_.front();
162 }
163
164 MEDIA_LOGI("Selected factory: 0x%{public}06" PRIXPTR ", score: %{public}d", FAKE_POINTER(target.get()), maxScore);
165 return target;
166 }
167 } // namespace Media
168 } // namespace OHOS
169