• 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 "dumper.h"
17 #include <string>
18 #include <unistd.h>
19 #include <cstdio>
20 #include <mutex>
21 #include <sys/time.h>
22 #include <securec.h>
23 #include <unordered_map>
24 #include "directory_ex.h"
25 #include "media_errors.h"
26 #include "media_log.h"
27 #include "param_wrapper.h"
28 
29 namespace {
30     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "GstDumper"};
31     static std::mutex g_padBufCountMutex;
32     static std::unordered_map<GstPad *, uint64_t> g_padBufCount = {};
33 }
34 
35 namespace OHOS {
36 namespace Media {
DumpDotGraph(GstPipeline & pipeline,int32_t oldState,int32_t newState)37 void Dumper::DumpDotGraph(GstPipeline &pipeline, int32_t oldState, int32_t newState)
38 {
39     if ((oldState < GST_STATE_VOID_PENDING) || (oldState > GST_STATE_PLAYING) ||
40         (newState < GST_STATE_VOID_PENDING) || (newState > GST_STATE_PLAYING)) {
41         MEDIA_LOGE("invalid state, oldState: %{public}d, newState: %{public}d", oldState, newState);
42         return;
43     }
44 
45     std::string dumpDir;
46     int res = OHOS::system::GetStringParameter("sys.media.dump.dot.path", dumpDir, "");
47     if (res != 0 || dumpDir.empty()) {
48         return;
49     }
50 
51     std::string realPath;
52     CHECK_AND_RETURN_LOG(PathToRealPath(dumpDir, realPath), "invalid dump path: %{public}s", dumpDir.c_str());
53 
54     struct timeval tv;
55     int ret = gettimeofday(&tv, nullptr);
56     CHECK_AND_RETURN_LOG(ret >= 0, "get time of day failed");
57 
58     constexpr int32_t secPerHour = 60 * 60;
59     constexpr int32_t minutePerHour = 60;
60     constexpr int32_t secPerMinute = 60;
61     constexpr int32_t usecPerMSec = 1000;
62 
63     uint64_t hour = static_cast<uint64_t>(tv.tv_sec / secPerHour);
64     uint32_t minute = static_cast<uint32_t>((tv.tv_sec / secPerMinute) % minutePerHour);
65     uint32_t sec = static_cast<uint32_t>(tv.tv_sec % minutePerHour);
66     uint32_t millsec = static_cast<uint32_t>(tv.tv_usec / usecPerMSec);
67 
68     const gchar *oldName = gst_element_state_get_name(static_cast<GstState>(oldState));
69     const gchar *newName = gst_element_state_get_name(static_cast<GstState>(newState));
70 
71     char fullPath[PATH_MAX] = { 0 };
72     const char *format = "%s/%" PRIu64 ".%u.%u.%u-media-pipeline.0x%06" PRIXPTR ".%s_%s.dot";
73     ret = sprintf_s(fullPath, PATH_MAX, format, realPath.c_str(), hour, minute, sec, millsec,
74                     FAKE_POINTER(&pipeline), oldName, newName);
75     if (ret <= 0) {
76         MEDIA_LOGE("dump dot failed for 0x%{public}06" PRIXPTR " %{public}s to %{public}s",
77                    FAKE_POINTER(&pipeline), oldName, newName);
78         return;
79     }
80 
81     FILE *fp = fopen(fullPath, "wb");
82     CHECK_AND_RETURN_LOG(fp != nullptr, "open path failed, %{public}s", fullPath);
83 
84     gchar *buf = gst_debug_bin_to_dot_data(GST_BIN(&pipeline), GST_DEBUG_GRAPH_SHOW_ALL);
85     if (buf != nullptr) {
86         (void)fputs(buf, fp);
87         g_free(buf);
88     } else {
89         MEDIA_LOGD("buf is nullptr");
90     }
91 
92     (void)fclose(fp);
93     MEDIA_LOGD("wrote pipeline graph to : '%{public}s'", fullPath);
94 }
95 
DumpGstBuffer(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)96 GstPadProbeReturn Dumper::DumpGstBuffer(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
97 {
98     (void)user_data;
99     CHECK_AND_RETURN_RET(pad != nullptr && info != nullptr, GST_PAD_PROBE_OK);
100 
101     if ((GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BUFFER) == 0) {
102         return GST_PAD_PROBE_OK;
103     }
104 
105     GstBuffer *buf = gst_pad_probe_info_get_buffer(info);
106     CHECK_AND_RETURN_RET(buf != nullptr, GST_PAD_PROBE_OK);
107     GstMapInfo mapInfo = GST_MAP_INFO_INIT;
108     CHECK_AND_RETURN_RET(gst_buffer_map(buf, &mapInfo, GST_MAP_READ), GST_PAD_PROBE_OK);
109 
110     uint64_t bufSeq = 0;
111     {
112         std::lock_guard<std::mutex> lock(g_padBufCountMutex);
113         if (g_padBufCount.count(pad) == 0) {
114             g_padBufCount.emplace(pad, 0);
115         }
116         bufSeq = g_padBufCount[pad]++;
117     }
118 
119     char fullPath[PATH_MAX] = { 0 };
120     const char *format = "/data/media/dump/pad_%s_%s_buf_%" PRIu64 "";
121     if (sprintf_s(fullPath, PATH_MAX, format, GST_DEBUG_PAD_NAME(pad), bufSeq) <= 0) {
122         MEDIA_LOGE("dump buffer failed for 0x%{public}06" PRIXPTR ", pad is %{public}s:%{public}s",
123                    FAKE_POINTER(buf), GST_DEBUG_PAD_NAME(pad));
124         gst_buffer_unmap(buf, &mapInfo);
125         return GST_PAD_PROBE_OK;
126     }
127 
128     FILE *fp = fopen(fullPath, "wb");
129     if (fp != nullptr) {
130         (void)fwrite(mapInfo.data, mapInfo.size, 1, fp);
131         (void)fflush(fp);
132         (void)fclose(fp);
133         fp = nullptr;
134     } else {
135         MEDIA_LOGE("open path failed, %{public}s", fullPath);
136     }
137 
138     gst_buffer_unmap(buf, &mapInfo);
139 
140     MEDIA_LOGD("wrote buffer to %{public}s", fullPath);
141     return GST_PAD_PROBE_OK;
142 }
143 
AddDumpGstBufferProbe(GstElement * element,const gchar * padname)144 void Dumper::AddDumpGstBufferProbe(GstElement *element, const gchar *padname)
145 {
146     GstPad *pad = gst_element_get_static_pad(element, padname);
147     CHECK_AND_RETURN(pad != nullptr);
148 
149     gulong ret = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, &Dumper::DumpGstBuffer, nullptr, nullptr);
150     if (ret == 0) {
151         MEDIA_LOGE("add dump gst buffer probe to pad %{public}s:%{public}s failed", GST_DEBUG_PAD_NAME(pad));
152     } else {
153         MEDIA_LOGD("add dump gst buffer probe to pad %{public}s:%{public}s success", GST_DEBUG_PAD_NAME(pad));
154     }
155 
156     gst_object_unref(pad);
157 }
158 
IsEnableDumpGstBuffer()159 bool Dumper::IsEnableDumpGstBuffer()
160 {
161     int value = OHOS::system::GetIntParameter("sys.media.dump.gstbuffer", 0);
162     if (value == 0) {
163         return false;
164     }
165 
166     return true;
167 }
168 } // namespace Media
169 } // namespace OHOS
170