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_player_track_parse.h"
17 #include "media_log.h"
18 #include "media_errors.h"
19
20 namespace {
21 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "GstPlayerTrackParse"};
22 }
23
24 namespace OHOS {
25 namespace Media {
26 static constexpr uint32_t MEDIA_TYPE_AUD = 0;
27 static constexpr uint32_t MEDIA_TYPE_VID = 1;
28 static const std::unordered_map<std::string_view, std::string> TRACK_FORMAT_STRING_CHANGE = {
29 {PlayerKeys::PLAYER_WIDTH, "width"}, {PlayerKeys::PLAYER_HEIGHT, "height"}, {PlayerKeys::PLAYER_MIME, "codec_mime"},
30 {PlayerKeys::PLAYER_BITRATE, "bitrate"}, {PlayerKeys::PLAYER_FRAMERATE, "framerate"},
31 {PlayerKeys::PLAYER_LANGUGAE, "language-code"}, {PlayerKeys::PLAYER_SAMPLE_RATE, "rate"},
32 {PlayerKeys::PLAYER_CHANNELS, "channels"},
33 };
Create()34 std::shared_ptr<GstPlayerTrackParse> GstPlayerTrackParse::Create()
35 {
36 std::shared_ptr<GstPlayerTrackParse> trackInfo = std::make_shared<GstPlayerTrackParse>();
37 return trackInfo;
38 }
39
GetVideoTrackInfo(std::vector<Format> & videoTrack)40 int32_t GstPlayerTrackParse::GetVideoTrackInfo(std::vector<Format> &videoTrack)
41 {
42 int32_t value;
43 for (auto iter = videoTrackInfo_.begin(); iter != videoTrackInfo_.end(); iter++) {
44 Format trackInfo;
45 auto trackInfoMap = iter->begin()->second;
46 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_MIME)) > 0) {
47 std::string strValue = trackInfoMap.at(std::string(PlayerKeys::PLAYER_MIME));
48 (void)trackInfo.PutStringValue(std::string(PlayerKeys::PLAYER_MIME), strValue);
49 }
50 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_BITRATE)) > 0) {
51 value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_BITRATE)));
52 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_BITRATE), value);
53 }
54 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_WIDTH)) > 0) {
55 value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_WIDTH)));
56 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_WIDTH), value);
57 }
58 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_HEIGHT)) > 0) {
59 value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_HEIGHT)));
60 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_HEIGHT), value);
61 }
62 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_FRAMERATE)) > 0) {
63 std::string framerate = trackInfoMap.at(std::string(PlayerKeys::PLAYER_FRAMERATE));
64 std::string::size_type delimPos = framerate.find('/');
65 if (delimPos == std::string::npos) {
66 MEDIA_LOGE("unrecognizable framerate, %{public}s", framerate.c_str());
67 return MSERR_UNKNOWN;
68 }
69 int32_t num = std::stoi(framerate.substr(0, delimPos));
70 int32_t den = std::stoi(framerate.substr(delimPos + 1, framerate.length()));
71 if (den != 0) {
72 /* 100: float to int ratio */
73 value = (static_cast<float>(num) / den) * 100;
74 } else {
75 value = num;
76 }
77
78 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_FRAMERATE), value);
79 }
80 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_TRACK_INDEX)) > 0) {
81 value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_TRACK_INDEX)));
82 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), value);
83 }
84 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_TYPE), MEDIA_TYPE_VID);
85 videoTrack.push_back(trackInfo);
86 }
87 return MSERR_OK;
88 }
89
GetAudioTrackInfo(std::vector<Format> & audioTrack)90 int32_t GstPlayerTrackParse::GetAudioTrackInfo(std::vector<Format> &audioTrack)
91 {
92 for (auto iter = audioTrackInfo_.begin(); iter != audioTrackInfo_.end(); iter++) {
93 Format trackInfo;
94 auto trackInfoMap = iter->begin()->second;
95 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_MIME)) > 0) {
96 std::string value = trackInfoMap.at(std::string(PlayerKeys::PLAYER_MIME));
97 (void)trackInfo.PutStringValue(std::string(PlayerKeys::PLAYER_MIME), value);
98 }
99 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_BITRATE)) > 0) {
100 int32_t value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_BITRATE)));
101 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_BITRATE), value);
102 }
103 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_SAMPLE_RATE)) > 0) {
104 int32_t value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_SAMPLE_RATE)));
105 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_SAMPLE_RATE), value);
106 }
107 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_CHANNELS)) > 0) {
108 int32_t value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_CHANNELS)));
109 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_CHANNELS), value);
110 }
111 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_LANGUGAE)) > 0) {
112 std::string value = trackInfoMap.at(std::string(PlayerKeys::PLAYER_LANGUGAE));
113 (void)trackInfo.PutStringValue(std::string(PlayerKeys::PLAYER_LANGUGAE), value);
114 }
115 if (trackInfoMap.count(std::string(PlayerKeys::PLAYER_TRACK_INDEX)) > 0) {
116 int32_t value = std::stoi(trackInfoMap.at(std::string(PlayerKeys::PLAYER_TRACK_INDEX)));
117 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), value);
118 }
119 (void)trackInfo.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_TYPE), MEDIA_TYPE_AUD);
120 audioTrack.push_back(trackInfo);
121 }
122 return MSERR_OK;
123 }
124
GetSerializedValue(const GValue * value)125 std::string GstPlayerTrackParse::GetSerializedValue(const GValue *value)
126 {
127 if (G_VALUE_HOLDS_STRING(value)) {
128 const gchar *str = g_value_get_string(value);
129 CHECK_AND_RETURN_RET_LOG(str != nullptr, "", "gvalue has no null value");
130 MEDIA_LOGI("value: %{public}s", str);
131 return std::string(str);
132 }
133
134 gchar *str = gst_value_serialize(value);
135 CHECK_AND_RETURN_RET_LOG(str != nullptr, "", "serialize value failed");
136 std::string serializedValue = str;
137 g_free(str);
138
139 return serializedValue;
140 }
141
ParseSingleCapsStructure(const GstStructure * struc,const GstPad * pad,std::vector<std::unordered_map<GstPad *,std::unordered_map<std::string,std::string>>> & trackInfoVec,std::vector<std::string_view> expectedCapsFields,int32_t index)142 void GstPlayerTrackParse::ParseSingleCapsStructure(const GstStructure *struc, const GstPad *pad,
143 std::vector<std::unordered_map<GstPad *, std::unordered_map<std::string, std::string>>> &trackInfoVec,
144 std::vector<std::string_view> expectedCapsFields, int32_t index)
145 {
146 std::unordered_map<std::string, std::string> trackMap;
147 std::string mime = gst_structure_get_name(struc);
148
149 (void)trackMap.insert(
150 std::pair<std::string, std::string>(std::string(PlayerKeys::PLAYER_TRACK_INDEX), std::to_string(index)));
151 (void)trackMap.insert(std::pair<std::string, std::string>(std::string(PlayerKeys::PLAYER_MIME), mime));
152 for (auto &field : expectedCapsFields) {
153 auto iterStr = TRACK_FORMAT_STRING_CHANGE.find(field);
154 if (iterStr == TRACK_FORMAT_STRING_CHANGE.end()) {
155 MEDIA_LOGE("not match expected cap, %{public}s", field.data());
156 continue;
157 }
158 const GValue *val = gst_structure_get_value(struc, iterStr->second.c_str());
159 if (val == nullptr) {
160 MEDIA_LOGE("get %{public}s filed data value error", iterStr->second.c_str());
161 continue;
162 }
163
164 std::string serializedValue = GetSerializedValue(val);
165 MEDIA_LOGD("field %{public}s val %{public}s", iterStr->second.c_str(), serializedValue.c_str());
166 trackMap.insert(std::pair<std::string, std::string>(std::string(field), serializedValue));
167 }
168 std::unordered_map<GstPad *, std::unordered_map<std::string, std::string>> padMap;
169 (void)padMap.insert(std::pair<GstPad *, std::unordered_map<std::string, std::string>>((GstPad *)pad, trackMap));
170 trackInfoVec.push_back(padMap);
171 }
172
GetMimeFromStruc(const GstStructure * struc,std::string & mime)173 int32_t GstPlayerTrackParse::GetMimeFromStruc(const GstStructure *struc, std::string &mime)
174 {
175 const gchar *name = gst_structure_get_name(struc);
176 if (name == nullptr) {
177 MEDIA_LOGE("gst_structure_get_name fail");
178 return MSERR_UNKNOWN;
179 }
180 std::string mimeType = name;
181 std::string::size_type delimPos = mimeType.find('/');
182 if (delimPos == std::string::npos) {
183 MEDIA_LOGE("unrecognizable mimetype, %{public}s", mimeType.c_str());
184 return MSERR_UNKNOWN;
185 }
186 MEDIA_LOGI("parse mimetype %{public}s's caps", mimeType.c_str());
187 mime = mimeType.substr(0, delimPos);
188 return MSERR_OK;
189 }
190
ParseStreamStruc(const GstPad * pad,GstPlayerTrackParse * playerTrackInfo)191 void GstPlayerTrackParse::ParseStreamStruc(const GstPad *pad, GstPlayerTrackParse *playerTrackInfo)
192 {
193 std::string mime;
194 GstStructure *structure;
195
196 int32_t retVal = GetStrucFromPad(pad, &structure);
197 if (retVal != MSERR_OK) {
198 return;
199 }
200 retVal = GetMimeFromStruc(structure, mime);
201 if (retVal != MSERR_OK) {
202 return;
203 }
204 if (mime.compare("video") == 0) {
205 std::vector<std::string_view> expectedCapsFields = {
206 PlayerKeys::PLAYER_WIDTH, PlayerKeys::PLAYER_HEIGHT, PlayerKeys::PLAYER_FRAMERATE
207 };
208 ParseSingleCapsStructure(structure, pad, playerTrackInfo->videoTrackInfo_,
209 expectedCapsFields, playerTrackInfo->trackIndex_);
210 playerTrackInfo->trackIndex_++;
211 } else if (mime.compare("audio") == 0) {
212 std::vector<std::string_view> expectedCapsFields = {
213 PlayerKeys::PLAYER_SAMPLE_RATE, PlayerKeys::PLAYER_CHANNELS
214 };
215 ParseSingleCapsStructure(structure, pad, playerTrackInfo->audioTrackInfo_,
216 expectedCapsFields, playerTrackInfo->trackIndex_);
217 playerTrackInfo->trackIndex_++;
218 } else {
219 MEDIA_LOGE("parse streamType %{public}s's not match", mime.c_str());
220 return;
221 }
222 }
223
GetStrucFromPad(const GstPad * pad,GstStructure ** struc)224 int32_t GstPlayerTrackParse::GetStrucFromPad(const GstPad *pad, GstStructure **struc)
225 {
226 GstCaps *caps = gst_pad_get_current_caps(const_cast<GstPad *>(pad));
227 if (caps == nullptr) {
228 MEDIA_LOGE("gst_pad_get_current_caps return nullptr");
229 return MSERR_UNKNOWN;
230 }
231
232 MEDIA_LOGD("add probe for %{public}s's pad %{public}s",
233 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)), GST_PAD_NAME(pad));
234
235 *struc = gst_caps_get_structure(caps, 0);
236 if (*struc == nullptr) {
237 MEDIA_LOGE("gst_caps_get_structure return nullptr");
238 return MSERR_UNKNOWN;
239 }
240 return MSERR_OK;
241 }
242
FindTrackInfoMap(const GstPad * pad,std::vector<std::unordered_map<GstPad *,std::unordered_map<std::string,std::string>>> & trackInfoVec)243 std::unordered_map<std::string, std::string> *GstPlayerTrackParse::FindTrackInfoMap(const GstPad *pad,
244 std::vector<std::unordered_map<GstPad *, std::unordered_map<std::string, std::string>>> &trackInfoVec)
245 {
246 for (auto iter = trackInfoVec.begin(); iter != trackInfoVec.end(); iter++) {
247 auto padToMapIt = iter->find(const_cast<GstPad *>(pad));
248 if (padToMapIt == iter->end()) {
249 return nullptr;
250 }
251 return &(padToMapIt->second);
252 }
253
254 return nullptr;
255 }
256
ParseTag(const GstTagList * tagList,guint tagIndex,std::vector<std::string_view> expectedTagFields,std::unordered_map<std::string,std::string> * trackInfoMap)257 void GstPlayerTrackParse::ParseTag(const GstTagList *tagList, guint tagIndex,
258 std::vector<std::string_view> expectedTagFields,
259 std::unordered_map<std::string, std::string> *trackInfoMap)
260 {
261 const gchar *tag = gst_tag_list_nth_tag_name(tagList, tagIndex);
262 if (tag == nullptr) {
263 return;
264 }
265
266 MEDIA_LOGD("visit tag: %{public}s", tag);
267 for (auto iter = expectedTagFields.begin(); iter != expectedTagFields.end(); iter++) {
268 auto iterStr = TRACK_FORMAT_STRING_CHANGE.find(*iter);
269 if (iterStr == TRACK_FORMAT_STRING_CHANGE.end()) {
270 MEDIA_LOGE("not match expected tag, %{public}s", iter->data());
271 continue;
272 }
273 if (iterStr->second.compare(tag) == 0) {
274 const GValue *value = gst_tag_list_get_value_index(tagList, tag, 0);
275 if (value == nullptr) {
276 MEDIA_LOGE("gst_tag_list_get_value_index get tag %{public}s fail", tag);
277 return;
278 }
279 std::string serializedValue = GetSerializedValue(value);
280 trackInfoMap->insert(std::pair<std::string, std::string>(std::string(*iter), serializedValue));
281 MEDIA_LOGD("trackInfoMap: %{public}s, %{public}s", iter->data(), serializedValue.c_str());
282 break;
283 }
284 }
285 }
286
ParseTagAndSaveTrackInfo(const GstPad * pad,const GstTagList * tagList,const std::vector<std::string_view> & expectedTagFields,std::vector<std::unordered_map<GstPad *,std::unordered_map<std::string,std::string>>> & trackInfoVec)287 void GstPlayerTrackParse::ParseTagAndSaveTrackInfo(const GstPad *pad, const GstTagList *tagList,
288 const std::vector<std::string_view> &expectedTagFields,
289 std::vector<std::unordered_map<GstPad *, std::unordered_map<std::string, std::string>>> &trackInfoVec)
290 {
291 std::unordered_map<std::string, std::string> *trackInfoMap;
292 gint tagCnt = gst_tag_list_n_tags(tagList);
293 if (tagCnt < 0) {
294 return;
295 }
296
297 trackInfoMap = FindTrackInfoMap(pad, trackInfoVec);
298 if (trackInfoMap == nullptr) {
299 MEDIA_LOGE("not find trackInfoMap at pad %{public}s", GST_PAD_NAME(pad));
300 return;
301 }
302
303 for (guint tagIndex = 0; tagIndex < static_cast<guint>(tagCnt); tagIndex++) {
304 ParseTag(tagList, tagIndex, expectedTagFields, trackInfoMap);
305 }
306 }
307
ParseTagList(const GstPad * pad,const GstTagList * tagList,GstPlayerTrackParse * playerTrackInfo)308 void GstPlayerTrackParse::ParseTagList(const GstPad *pad, const GstTagList *tagList,
309 GstPlayerTrackParse *playerTrackInfo)
310 {
311 std::vector<std::string_view> expectedTagFields;
312 GstStructure *structure;
313 std::string mime;
314
315 int32_t retVal = GetStrucFromPad(pad, &structure);
316 if (retVal != MSERR_OK) {
317 return;
318 }
319 retVal = GetMimeFromStruc(structure, mime);
320 if (retVal != MSERR_OK) {
321 return;
322 }
323 if (mime.compare("video") == 0) {
324 expectedTagFields = {PlayerKeys::PLAYER_BITRATE};
325 ParseTagAndSaveTrackInfo(pad, tagList, expectedTagFields, playerTrackInfo->videoTrackInfo_);
326 } else if (mime.compare("audio") == 0) {
327 expectedTagFields = {PlayerKeys::PLAYER_BITRATE, PlayerKeys::PLAYER_LANGUGAE};
328 ParseTagAndSaveTrackInfo(pad, tagList, expectedTagFields, playerTrackInfo->audioTrackInfo_);
329 } else {
330 MEDIA_LOGE("parse streamType %{public}s's not match", mime.c_str());
331 return;
332 }
333 }
334
ProbeCallback(GstPad * pad,GstPadProbeInfo * info,gpointer usrdata)335 GstPadProbeReturn GstPlayerTrackParse::ProbeCallback(GstPad *pad, GstPadProbeInfo *info, gpointer usrdata)
336 {
337 if (pad == nullptr || info == nullptr || usrdata == nullptr) {
338 MEDIA_LOGE("param is invalid");
339 return GST_PAD_PROBE_OK;
340 }
341
342 if (static_cast<unsigned int>(info->type) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
343 GstEvent *event = gst_pad_probe_info_get_event(info);
344 CHECK_AND_RETURN_RET_LOG(event != nullptr, GST_PAD_PROBE_OK, "event is null");
345 if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
346 GstTagList *tagList = nullptr;
347 gst_event_parse_tag(event, &tagList);
348 if (tagList == nullptr) {
349 MEDIA_LOGE("taglist is invalid");
350 return GST_PAD_PROBE_OK;
351 }
352 MEDIA_LOGI("catch tags at pad %{public}s", GST_PAD_NAME(pad));
353 ParseTagList(pad, tagList, reinterpret_cast<GstPlayerTrackParse *>(usrdata));
354 }
355 }
356
357 return GST_PAD_PROBE_OK;
358 }
359
AddProbeToPad(const GstPad * pad,GstPlayerTrackParse * playerTrackInfo)360 void GstPlayerTrackParse::AddProbeToPad(const GstPad *pad, GstPlayerTrackParse *playerTrackInfo)
361 {
362 gulong probeId = gst_pad_add_probe(const_cast<GstPad *>(pad), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
363 ProbeCallback, playerTrackInfo, nullptr);
364 if (probeId == 0) {
365 MEDIA_LOGE("add probe for %{public}s's pad %{public}s failed",
366 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)), GST_PAD_NAME(pad));
367 return;
368 }
369 (void)playerTrackInfo->padProbes_.insert(std::pair<GstPad *, gulong>((GstPad *)pad, probeId));
370 }
371
OnPadAddedCb(const GstElement * element,const GstPad * pad,GstPlayerTrackParse * playerTrackInfo)372 void GstPlayerTrackParse::OnPadAddedCb(const GstElement *element,
373 const GstPad *pad, GstPlayerTrackParse *playerTrackInfo)
374 {
375 CHECK_AND_RETURN_LOG(element != nullptr, "element is null");
376 CHECK_AND_RETURN_LOG(playerTrackInfo != nullptr, "playerTrackInfo is null");
377 CHECK_AND_RETURN_LOG(pad != nullptr, "pad is null");
378
379 ParseStreamStruc(pad, playerTrackInfo);
380 AddProbeToPad(pad, playerTrackInfo);
381 }
382
SetDemuxerElementFind(bool isFind)383 void GstPlayerTrackParse::SetDemuxerElementFind(bool isFind)
384 {
385 demuxerElementFind_ = isFind;
386 }
387
GetDemuxerElementFind()388 bool GstPlayerTrackParse::GetDemuxerElementFind()
389 {
390 return demuxerElementFind_;
391 }
392 } // namespace Media
393 } // namespace OHOS
394