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