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_msg_converter.h"
17 #include <functional>
18 #include <unordered_map>
19 #include "media_errors.h"
20 #include "media_log.h"
21 #include "gst_utils.h"
22
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "GstMsgConvDefault"};
25 }
26
27 namespace OHOS {
28 namespace Media {
StreamDecErrorParse(const gchar * name)29 static int32_t StreamDecErrorParse(const gchar *name)
30 {
31 if (strstr(name, "aac") != nullptr) {
32 MEDIA_LOGE("tag: MSERR_AUD_DEC_FAILED");
33 return MSERR_AUD_DEC_FAILED;
34 } else if (strstr(name, "h264") != nullptr || strstr(name, "h265") != nullptr) {
35 MEDIA_LOGE("tag: MSERR_VID_DEC_FAILED");
36 return MSERR_VID_DEC_FAILED;
37 } else {
38 MEDIA_LOGE("tag: MSERR_UNKNOWN");
39 return MSERR_UNKNOWN;
40 }
41 }
42
43 using StreamToServiceErrFunc = std::function<int32_t(const gchar*)>;
44 static const std::unordered_map<int32_t, StreamToServiceErrFunc> STREAM_TO_SERVICE_ERR_FUNC_TABLE = {
45 { GST_STREAM_ERROR_DECODE, StreamDecErrorParse },
46 };
47 static const std::unordered_map<int32_t, MediaServiceErrCode> STREAM_TO_SERVICE_ERR_TABLE = {
48 { GST_STREAM_ERROR_FORMAT, MSERR_UNSUPPORT_CONTAINER_TYPE },
49 { GST_STREAM_ERROR_TYPE_NOT_FOUND, MSERR_NOT_FIND_CONTAINER },
50 /* Currently, audio decoding and video decoding cannot be distinguished which is not supported by msg.
51 * By default, we set video decoding is not supported.
52 * The identification method must be added when the new demux pulgin in is use.
53 */
54 { GST_STREAM_ERROR_CODEC_NOT_FOUND, MSERR_UNSUPPORT_VID_DEC_TYPE },
55 { GST_STREAM_ERROR_DEMUX, MSERR_DEMUXER_FAILED },
56 { GST_STREAM_ERROR_WRONG_TYPE, MSERR_UNSUPPORT_FILE },
57 { GST_STREAM_ERROR_FAILED, MSERR_UNSUPPORT_STREAM },
58 };
59 static const std::unordered_map<int32_t, MediaServiceErrCode> RESOURCE_TO_SERVICE_ERR_TABLE = {
60 { GST_RESOURCE_ERROR_NOT_FOUND, MSERR_OPEN_FILE_FAILED },
61 { GST_RESOURCE_ERROR_OPEN_READ, MSERR_OPEN_FILE_FAILED },
62 { GST_RESOURCE_ERROR_READ, MSERR_FILE_ACCESS_FAILED },
63 { GST_RESOURCE_ERROR_NOT_AUTHORIZED, MSERR_FILE_ACCESS_FAILED },
64 { GST_RESOURCE_ERROR_TIME_OUT, MSERR_NETWORK_TIMEOUT },
65 };
66
StreamErrorParse(const gchar * name,const GError * error)67 static int32_t StreamErrorParse(const gchar *name, const GError *error)
68 {
69 CHECK_AND_RETURN_RET_LOG(name != nullptr, MSERR_UNSUPPORT_STREAM, "name is nullptr");
70 MEDIA_LOGE("domain: GST_STREAM_ERROR(%{public}d)", error->code);
71 auto streamIter = STREAM_TO_SERVICE_ERR_TABLE.find(error->code);
72 if (streamIter != STREAM_TO_SERVICE_ERR_TABLE.end()) {
73 return streamIter->second;
74 }
75 auto streamFuncIter = STREAM_TO_SERVICE_ERR_FUNC_TABLE.find(error->code);
76 if (streamFuncIter != STREAM_TO_SERVICE_ERR_FUNC_TABLE.end()) {
77 return streamFuncIter->second(name);
78 }
79
80 return MSERR_UNSUPPORT_STREAM;
81 }
82
ResourceErrorParse(const GError * error)83 static int32_t ResourceErrorParse(const GError *error)
84 {
85 MEDIA_LOGE("domain: GST_RESOURCE_ERROR");
86 auto resIter = RESOURCE_TO_SERVICE_ERR_TABLE.find(error->code);
87 if (resIter == RESOURCE_TO_SERVICE_ERR_TABLE.end()) {
88 return MSERR_UNSUPPORT_SOURCE;
89 }
90 return resIter->second;
91 }
92
ConvertErrorMessage(GstMessage & gstMsg,InnerMessage & innerMsg)93 static int32_t ConvertErrorMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
94 {
95 GError *error = nullptr;
96 gchar *debug = nullptr;
97 gst_message_parse_error(&gstMsg, &error, &debug);
98 if (error == nullptr || debug == nullptr) {
99 return MSERR_UNKNOWN;
100 }
101 MEDIA_LOGE("[ERROR] %{public}s, %{public}s", error->message, debug);
102
103 gchar *name = gst_object_get_path_string(gstMsg.src);
104 innerMsg.type = INNER_MSG_ERROR;
105 if (error->domain == GST_STREAM_ERROR) {
106 innerMsg.detail1 = StreamErrorParse(name, error);
107 } else if (error->domain == GST_RESOURCE_ERROR) {
108 innerMsg.detail1 = ResourceErrorParse(error);
109 } else {
110 innerMsg.detail1 = MSERR_UNSUPPORT_STREAM;
111 }
112 innerMsg.extend = std::string(error->message);
113
114 g_error_free(error);
115 g_free(debug);
116 g_free(name);
117 return MSERR_OK;
118 }
119
ConvertWarningMessage(GstMessage & gstMsg,InnerMessage & innerMsg)120 static int32_t ConvertWarningMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
121 {
122 GError *error = nullptr;
123 gchar *debug = nullptr;
124 gst_message_parse_warning(&gstMsg, &error, &debug);
125 if (error == nullptr || debug == nullptr) {
126 return MSERR_UNKNOWN;
127 }
128 MEDIA_LOGW("[WARNING] %{public}s, %{public}s", error->message, debug);
129
130 innerMsg.type = INNER_MSG_WARNING;
131 innerMsg.detail1 = MSERR_UNKNOWN;
132
133 g_error_free(error);
134 g_free(debug);
135 return MSERR_OK;
136 }
137
ConvertInfoMessage(GstMessage & gstMsg,InnerMessage & innerMsg)138 static int32_t ConvertInfoMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
139 {
140 GError *error = nullptr;
141 gchar *debug = nullptr;
142 gst_message_parse_info(&gstMsg, &error, &debug);
143 if (error == nullptr || debug == nullptr) {
144 return MSERR_UNKNOWN;
145 }
146 MEDIA_LOGI("[INFO] %{public}s, %{public}s", error->message, debug);
147
148 innerMsg.type = INNER_MSG_INFO;
149 innerMsg.detail1 = MSERR_UNKNOWN;
150
151 g_error_free(error);
152 g_free(debug);
153 return MSERR_OK;
154 }
155
ConvertStateChangedMessage(GstMessage & gstMsg,InnerMessage & innerMsg)156 static int32_t ConvertStateChangedMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
157 {
158 GstState oldState = GST_STATE_VOID_PENDING;
159 GstState newState = GST_STATE_VOID_PENDING;
160 GstState pendingState = GST_STATE_VOID_PENDING;
161 gst_message_parse_state_changed(&gstMsg, &oldState, &newState, &pendingState);
162 MEDIA_LOGI("%{public}s change state from %{public}s to %{public}s", ELEM_NAME(GST_MESSAGE_SRC(&gstMsg)),
163 gst_element_state_get_name(oldState), gst_element_state_get_name(newState));
164
165 innerMsg.type = INNER_MSG_STATE_CHANGED;
166 innerMsg.detail1 = static_cast<int32_t>(oldState);
167 innerMsg.detail2 = static_cast<int32_t>(newState);
168 if (GST_IS_PIPELINE(gstMsg.src)) {
169 GstPipeline *pipeline = GST_PIPELINE(GST_MESSAGE_SRC(&gstMsg));
170 innerMsg.extend = pipeline;
171 }
172
173 return MSERR_OK;
174 }
175
ConvertAsyncDoneMessage(GstMessage & gstMsg,InnerMessage & innerMsg)176 static int32_t ConvertAsyncDoneMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
177 {
178 innerMsg.type = INNER_MSG_ASYNC_DONE;
179 if (GST_IS_PIPELINE(gstMsg.src)) {
180 GstPipeline *pipeline = GST_PIPELINE(GST_MESSAGE_SRC(&gstMsg));
181 innerMsg.extend = pipeline;
182 }
183
184 return MSERR_OK;
185 }
186
ConvertResolutionChangedMessage(GstMessage & gstMsg,InnerMessage & innerMsg)187 static int32_t ConvertResolutionChangedMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
188 {
189 gint width = 0;
190 gint height = 0;
191 gst_message_parse_resulution_changed(&gstMsg, &width, &height);
192 MEDIA_LOGI("resolution changed to width:%{public}d height:%{public}d", width, height);
193
194 innerMsg.type = INNER_MSG_RESOLUTION_CHANGED;
195 innerMsg.detail1 = width;
196 innerMsg.detail2 = height;
197 return MSERR_OK;
198 }
199
ConvertBufferingTimeMessage(GstMessage & gstMsg,InnerMessage & innerMsg)200 static int32_t ConvertBufferingTimeMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
201 {
202 gint64 bufferingTime;
203 guint mqNumId;
204 gst_message_parse_buffering_time(&gstMsg, &bufferingTime, &mqNumId);
205 MEDIA_LOGI("mqNumId = %{public}u, bufferingTime = %{public}" PRIi64 "", mqNumId, bufferingTime);
206
207 innerMsg.type = INNER_MSG_BUFFERING_TIME;
208 innerMsg.detail1 = static_cast<int32_t>(mqNumId);
209 innerMsg.extend = bufferingTime;
210 return MSERR_OK;
211 }
212
ConvertUsedMqNumMessage(GstMessage & gstMsg,InnerMessage & innerMsg)213 static int32_t ConvertUsedMqNumMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
214 {
215 guint usedMqNum;
216 gst_message_parse_mq_num_use_buffering(&gstMsg, &usedMqNum);
217 MEDIA_LOGI("used multiqueue num for buffering is %{public}u", usedMqNum);
218
219 innerMsg.type = INNER_MSG_BUFFERING_USED_MQ_NUM;
220 innerMsg.detail1 = static_cast<int32_t>(usedMqNum);
221 return MSERR_OK;
222 }
223
ConvertVideoRotationMessage(GstMessage & gstMsg,InnerMessage & innerMsg)224 static int32_t ConvertVideoRotationMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
225 {
226 gchar *rotation = NULL;
227 gst_message_parse_video_rotation(&gstMsg, &rotation);
228 MEDIA_LOGI("Rotation is %{public}s", rotation);
229
230 std::string str(rotation);
231 std::string::size_type pos = std::string::npos;
232 if ((pos = str.find("-")) == std::string::npos) {
233 return MSERR_INVALID_VAL;
234 }
235 std::string subStr = str.substr(pos + 1);
236 int32_t rotate = std::stol(subStr, nullptr, 10); // 10, decimalism
237 MEDIA_LOGI("Get rotate is %{public}d", rotate);
238
239 innerMsg.type = INNER_MSG_VIDEO_ROTATION;
240 innerMsg.detail1 = rotate;
241 return MSERR_OK;
242 }
243
ConvertElementMessage(GstMessage & gstMsg,InnerMessage & innerMsg)244 static int32_t ConvertElementMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
245 {
246 const GstStructure *s = gst_message_get_structure(&gstMsg);
247 if (gst_structure_has_name(s, "resolution-changed")) {
248 return ConvertResolutionChangedMessage(gstMsg, innerMsg);
249 } else if (gst_structure_has_name(s, "message-buffering-time")) {
250 return ConvertBufferingTimeMessage(gstMsg, innerMsg);
251 } else if (gst_structure_has_name(s, "message-mq-num-use-buffering")) {
252 return ConvertUsedMqNumMessage(gstMsg, innerMsg);
253 } else if (gst_structure_has_name(s, "video-rotation")) {
254 return ConvertVideoRotationMessage(gstMsg, innerMsg);
255 }
256
257 return MSERR_OK;
258 }
259
ConvertBufferingMessage(GstMessage & gstMsg,InnerMessage & innerMsg)260 static int32_t ConvertBufferingMessage(GstMessage &gstMsg, InnerMessage &innerMsg)
261 {
262 gchar *eleName = gst_element_get_name(GST_MESSAGE_SRC(&gstMsg));
263 if ((GST_MESSAGE_SRC(&gstMsg) != nullptr) && (strncmp(eleName, "queue2", strlen("queue2")) == 0)) {
264 MEDIA_LOGD("buffering msg comes from queue2, do not handle it");
265 g_free(eleName);
266 return MSERR_OK;
267 }
268
269 gint percent;
270 gst_message_parse_buffering (&gstMsg, &percent);
271 MEDIA_LOGI("multiqueue percent is %{public}d", percent);
272
273 innerMsg.type = INNER_MSG_BUFFERING;
274 innerMsg.detail1 = percent;
275 g_free(eleName);
276 return MSERR_OK;
277 }
278
279 static const std::unordered_map<GstMessageType, InnerMsgType> SIMPLE_MSG_TYPE_MAPPING = {
280 { GST_MESSAGE_DURATION_CHANGED, INNER_MSG_DURATION_CHANGED },
281 { GST_MESSAGE_EOS, INNER_MSG_EOS },
282 };
283
284 using MsgConvFunc = std::function<int32_t(GstMessage&, InnerMessage&)>;
285 static const std::unordered_map<GstMessageType, MsgConvFunc> MSG_CONV_FUNC_TABLE = {
286 { GST_MESSAGE_ERROR, ConvertErrorMessage },
287 { GST_MESSAGE_WARNING, ConvertWarningMessage },
288 { GST_MESSAGE_INFO, ConvertInfoMessage },
289 { GST_MESSAGE_STATE_CHANGED, ConvertStateChangedMessage },
290 { GST_MESSAGE_ASYNC_DONE, ConvertAsyncDoneMessage },
291 { GST_MESSAGE_ELEMENT, ConvertElementMessage },
292 { GST_MESSAGE_BUFFERING, ConvertBufferingMessage },
293 };
294
ConvertToInnerMsg(GstMessage & gstMsg,InnerMessage & innerMsg) const295 int32_t GstMsgConverterDefault::ConvertToInnerMsg(GstMessage &gstMsg, InnerMessage &innerMsg) const
296 {
297 innerMsg.type = INNER_MSG_UNKNOWN;
298
299 if (SIMPLE_MSG_TYPE_MAPPING.count(gstMsg.type) != 0) {
300 innerMsg.type = SIMPLE_MSG_TYPE_MAPPING.at(gstMsg.type);
301 MEDIA_LOGI("convert gst msg type: %{public}s", GST_MESSAGE_TYPE_NAME(&gstMsg));
302 return MSERR_OK;
303 }
304
305 if (MSG_CONV_FUNC_TABLE.count(gstMsg.type) == 0) {
306 return MSERR_OK;
307 }
308
309 return MSG_CONV_FUNC_TABLE.at(gstMsg.type)(gstMsg, innerMsg);
310 }
311 } // namespace Media
312 } // namespace OHOS