• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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