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