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 "gst_loader.h"
17 #include <string>
18 #include <map>
19 #include <queue>
20 #include <glib.h>
21 #include <gst/gst.h>
22 #include "string_ex.h"
23 #include "param_wrapper.h"
24 #include "media_errors.h"
25 #include "media_log.h"
26 #include "engine_dump_manager.h"
27
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "GstLoader"};
30 const std::map<char, GstDebugLevel> LOG_LEVEL_TO_GST_LEVEL = {
31 {'E', GST_LEVEL_ERROR},
32 {'W', GST_LEVEL_WARNING},
33 {'I', GST_LEVEL_INFO},
34 {'D', GST_LEVEL_DEBUG},
35 {'L', GST_LEVEL_LOG},
36 {'T', GST_LEVEL_TRACE},
37 };
38 const std::string g_gstDftTag = "*";
39 const std::string g_gstVdecTag = "vdecbase";
40 const std::string g_gstVencTag = "vencbase";
41 const std::string g_gstSurfaceTag = "prosurallocator";
42 const std::string g_gstCurlTag = "curlhttpsrc";
43 const std::vector<const gchar *> GST_ARGS = {
44 "ohos_media_service",
45 "--gst-disable-registry-fork",
46 #if (defined(__aarch64__) || defined(__x86_64__))
47 "--gst-plugin-path=/system/lib64/media/plugins"
48 #else
49 "--gst-plugin-path=/system/lib/media/plugins"
50 #endif
51 };
52 }
53
54 namespace OHOS {
55 namespace Media {
56 struct GstLogPrintInfo {
57 GstDebugLevel level;
58 const gchar *file;
59 const gchar *function;
60 gint line;
61 GObject *object;
62 const char *logMsg;
63 const char *modeName;
64 };
65
66 #ifdef OHOS_MEDIA_LOG_DFX
GstLogPrint(const GstLogPrintInfo & info)67 static void GstLogPrint(const GstLogPrintInfo &info)
68 {
69 const gchar *objName = GST_IS_OBJECT(info.object) ? GST_OBJECT_NAME(info.object) : " ";
70 objName = objName ? objName : " ";
71 OHOS::HiviewDFX::HiLogLabel gstLable = {LOG_CORE, LOG_DOMAIN, info.modeName};
72
73 switch (info.level) {
74 case GST_LEVEL_TRACE: // no break
75 case GST_LEVEL_LOG: // no break
76 case GST_LEVEL_DEBUG:
77 DfxLogDump::GetInstance().SaveLog("LOGD", gstLable, "{%s():%d} [gst::%s:%" PRIXPTR "] %s",
78 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
79 (void)HILOG_IMPL(LOG_CORE, LOG_DEBUG, LOG_DOMAIN, gstLable.tag,
80 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
81 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
82 break;
83 case GST_LEVEL_INFO:
84 DfxLogDump::GetInstance().SaveLog("LOGI", gstLable, "{%s():%d} [gst::%s:%" PRIXPTR "] %s",
85 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
86 (void)HILOG_IMPL(LOG_CORE, LOG_INFO, LOG_DOMAIN, gstLable.tag,
87 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
88 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
89 break;
90 case GST_LEVEL_WARNING:
91 DfxLogDump::GetInstance().SaveLog("LOGW", gstLable, "{%s():%d} [gst::%s:%" PRIXPTR "] %s",
92 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
93 (void)HILOG_IMPL(LOG_CORE, LOG_WARN, LOG_DOMAIN, gstLable.tag,
94 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
95 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
96 break;
97 case GST_LEVEL_ERROR:
98 DfxLogDump::GetInstance().SaveLog("LOGE", gstLable, "{%s():%d} [gst::%s:%" PRIXPTR "] %s",
99 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
100 (void)HILOG_IMPL(LOG_CORE, LOG_ERROR, LOG_DOMAIN, gstLable.tag,
101 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
102 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
103 break;
104 default:
105 break;
106 }
107 }
108 #else
GstLogPrint(const GstLogPrintInfo & info)109 static void GstLogPrint(const GstLogPrintInfo &info)
110 {
111 const gchar *objName = GST_IS_OBJECT(info.object) ? GST_OBJECT_NAME(info.object) : " ";
112 objName = objName ? objName : " ";
113 OHOS::HiviewDFX::HiLogLabel gstLable = {LOG_CORE, LOG_DOMAIN, info.modeName};
114
115 switch (info.level) {
116 case GST_LEVEL_TRACE: // no break
117 case GST_LEVEL_LOG: // no break
118 case GST_LEVEL_DEBUG:
119 (void)HILOG_IMPL(LOG_CORE, LOG_DEBUG, LOG_DOMAIN, gstLable.tag,
120 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
121 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
122 break;
123 case GST_LEVEL_INFO:
124 (void)HILOG_IMPL(LOG_CORE, LOG_INFO, LOG_DOMAIN, gstLable.tag,
125 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
126 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
127 break;
128 case GST_LEVEL_WARNING:
129 (void)HILOG_IMPL(LOG_CORE, LOG_WARN, LOG_DOMAIN, gstLable.tag,
130 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
131 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
132 break;
133 case GST_LEVEL_ERROR:
134 (void)HILOG_IMPL(LOG_CORE, LOG_ERROR, LOG_DOMAIN, gstLable.tag,
135 "{%{public}s():%{public}d} [gst::%{public}s:%{public}" PRIXPTR "] %{public}s",
136 info.function, info.line, objName, FAKE_POINTER(info.object), info.logMsg);
137 break;
138 default:
139 break;
140 }
141 }
142 #endif
143
GstLogCallbackFunc(GstDebugCategory * category,GstDebugLevel level,const gchar * file,const gchar * function,gint line,GObject * object,GstDebugMessage * message,gpointer userData)144 static void GstLogCallbackFunc(GstDebugCategory *category, GstDebugLevel level, const gchar *file,
145 const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer userData)
146 {
147 const gchar *modeName = nullptr;
148 (void)userData;
149
150 if (message == nullptr) {
151 return;
152 }
153 if (category != nullptr) {
154 if (level > gst_debug_category_get_threshold(category)) {
155 return;
156 }
157 modeName = gst_debug_category_get_name(category);
158 } else {
159 if (level > gst_debug_get_default_threshold()) {
160 return;
161 }
162 }
163
164 if (modeName == nullptr) {
165 modeName = LABEL.tag;
166 }
167
168 const gchar *logMsg = gst_debug_message_get(message);
169 if (logMsg == nullptr) {
170 return;
171 }
172 GstLogPrintInfo printInfo = {level, file ? file : " ", function ? function : " ", line, object, logMsg, modeName};
173 GstLogPrint(printInfo);
174 }
175
GLogCallbackFunc(const gchar * logDomain,GLogLevelFlags level,const gchar * message,gpointer userData)176 static void GLogCallbackFunc(const gchar *logDomain, GLogLevelFlags level, const gchar *message, gpointer userData)
177 {
178 const gchar *modeName = logDomain;
179 (void)userData;
180
181 if (message == nullptr || level > G_LOG_LEVEL_WARNING) {
182 return;
183 }
184
185 if (modeName == nullptr) {
186 modeName = LABEL.tag;
187 }
188 OHOS::HiviewDFX::HiLogLabel glibLable = {LOG_CORE, LOG_DOMAIN, modeName};
189
190 switch (level) {
191 case G_LOG_LEVEL_WARNING:
192 (void)HILOG_IMPL(LOG_CORE, LOG_WARN, LOG_DOMAIN, glibLable.tag, "[glog] %{public}s", message);
193 break;
194 case G_LOG_LEVEL_CRITICAL: // no break
195 case G_LOG_LEVEL_ERROR: // no break
196 case G_LOG_FLAG_RECURSION:
197 (void)HILOG_IMPL(LOG_CORE, LOG_ERROR, LOG_DOMAIN, glibLable.tag, "[glog] %{public}s", message);
198 break;
199 default:
200 break;
201 }
202 }
203
EnableGLog(GLogFunc func)204 static void EnableGLog(GLogFunc func)
205 {
206 // map glib default log handler, and gstreamer log hander to GLogMap
207 (void)g_log_set_default_handler(func, nullptr);
208 (void)g_log_set_handler("GStreamer", static_cast<GLogLevelFlags>(0xFFFFFFFF), func, nullptr);
209 }
210
SetGstLogLevelFromSysPara()211 static void SetGstLogLevelFromSysPara()
212 {
213 std::string levelPara;
214 int res = OHOS::system::GetStringParameter("sys.media.log.level", levelPara, "");
215 if (res != 0 || levelPara.empty()) {
216 gst_debug_set_default_threshold(GST_LEVEL_WARNING);
217 MEDIA_LOGD("sys.media.log.level not find");
218 } else {
219 MEDIA_LOGD("sys.media.log.level=%{public}s", levelPara.c_str());
220 }
221
222 static std::map<std::string, char> logTagLevelMap = {
223 { g_gstDftTag, 'W' },
224 { g_gstVdecTag, 'D' },
225 { g_gstVencTag, 'D' },
226 { g_gstSurfaceTag, 'D' },
227 { g_gstCurlTag, 'D' },
228 };
229 std::vector<std::string> tagLevelVec;
230 SplitStr(levelPara, ",", tagLevelVec, false, true);
231 for (auto &tagLevel : tagLevelVec) {
232 std::vector<std::string> item;
233 SplitStr(tagLevel, ":", item, false, true); // module format:"tagname:level"
234 if (item.size() < 2) { // module format:"tagname:level"
235 continue;
236 }
237 const std::string &tag = item[0];
238 if (tag.size() >= 128) { // max tag size is 128
239 continue;
240 }
241 if (logTagLevelMap.size() >= 512 && logTagLevelMap.count(tag) == 0) { // 512 is max tag number
242 continue;
243 }
244 const std::string &level = item[1];
245 if (level.empty() || LOG_LEVEL_TO_GST_LEVEL.count(level.c_str()[0]) == 0) {
246 continue;
247 }
248
249 logTagLevelMap[tag] = level.c_str()[0];
250 MEDIA_LOGI("logPrara:%{public}s:%{public}c", tag.c_str(), level.c_str()[0]);
251 }
252 gst_debug_set_default_threshold(LOG_LEVEL_TO_GST_LEVEL.at(logTagLevelMap[g_gstDftTag]));
253 for (auto &&[tag, levelCode] : logTagLevelMap) {
254 if (tag == g_gstDftTag) {
255 continue;
256 }
257 GstDebugCategory *cat = _gst_debug_get_category(tag.c_str());
258 if (cat == nullptr) {
259 continue;
260 }
261 gst_debug_category_set_threshold(cat, LOG_LEVEL_TO_GST_LEVEL.at(logTagLevelMap[tag]));
262 }
263 }
264
CreateGstInitArgv()265 static gchar ***CreateGstInitArgv()
266 {
267 gchar ***argv = nullptr;
268 argv = static_cast<gchar ***>(new (std::nothrow) (gchar **));
269 if (argv == nullptr) {
270 MEDIA_LOGI("new argv failed");
271 return nullptr;
272 }
273 *argv = static_cast<gchar **>(new (std::nothrow) gchar *[GST_ARGS.size()]);
274 if (*argv == nullptr) {
275 delete argv;
276 return nullptr;
277 }
278 for (size_t i = 0; i < GST_ARGS.size(); i++) {
279 (*argv)[i] = const_cast<gchar *>(GST_ARGS[i]);
280 }
281
282 return argv;
283 }
284
DestroyGstInitArgv(gchar *** argv)285 static void DestroyGstInitArgv(gchar ***argv)
286 {
287 if (argv == nullptr) {
288 return;
289 }
290 if (*argv == nullptr) {
291 delete argv;
292 return;
293 }
294 delete [] *argv;
295 delete argv;
296 }
297
SetUp()298 int32_t GstLoader::SetUp()
299 {
300 std::lock_guard<std::mutex> lock(mutex_);
301 if (isInit_) {
302 return MSERR_OK;
303 }
304 EngineDumpManager::GetInstance().Init();
305
306 EnableGLog(GLogCallbackFunc);
307 gst_debug_remove_log_function(gst_debug_log_default);
308 gst_debug_add_log_function(GstLogCallbackFunc, nullptr, nullptr);
309 SetGstLogLevelFromSysPara();
310 int32_t argc = static_cast<int32_t>(GST_ARGS.size());
311 MEDIA_LOGI("SetUp GstLoader argc=%{public}d", argc);
312 gchar ***argv = CreateGstInitArgv();
313 if (argv == nullptr) {
314 return MSERR_NO_MEMORY;
315 }
316 gst_init(&argc, argv);
317 DestroyGstInitArgv(argv);
318 isInit_ = true;
319
320 MEDIA_LOGI("SetUp GstLoader finished!");
321
322 return MSERR_OK;
323 }
324
UpdateLogLevel() const325 void GstLoader::UpdateLogLevel() const
326 {
327 SetGstLogLevelFromSysPara();
328 }
329 } // namespace Media
330 } // namespace OHOS
331