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 "player_track_parse.h"
17 #include "media_log.h"
18 #include "media_errors.h"
19 #include "av_common.h"
20 #include "gst_utils.h"
21 #include "gst_meta_parser.h"
22 #include "player.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayerTrackParse"};
26 }
27
28 namespace OHOS {
29 namespace Media {
30 static const std::unordered_map<std::string_view, std::string_view> INNER_KEY_TO_PLAYER_KEY = {
31 { INNER_META_KEY_BITRATE, PlayerKeys::PLAYER_BITRATE },
32 { INNER_META_KEY_CHANNEL_COUNT, PlayerKeys::PLAYER_CHANNELS },
33 { INNER_META_KEY_FRAMERATE, PlayerKeys::PLAYER_FRAMERATE },
34 { INNER_META_KEY_VIDEO_HEIGHT, PlayerKeys::PLAYER_HEIGHT },
35 { INNER_META_KEY_LANGUAGE, PlayerKeys::PLAYER_LANGUGAE },
36 { INNER_META_KEY_MIME_TYPE, PlayerKeys::PLAYER_MIME },
37 { INNER_META_KEY_SAMPLE_RATE, PlayerKeys::PLAYER_SAMPLE_RATE },
38 { INNER_META_KEY_TRACK_INDEX, PlayerKeys::PLAYER_TRACK_INDEX },
39 { INNER_META_KEY_TRACK_TYPE, PlayerKeys::PLAYER_TRACK_TYPE },
40 { INNER_META_KEY_VIDEO_WIDTH, PlayerKeys::PLAYER_WIDTH },
41 };
42
Create()43 std::shared_ptr<PlayerTrackParse> PlayerTrackParse::Create()
44 {
45 std::shared_ptr<PlayerTrackParse> trackInfo = std::make_shared<PlayerTrackParse>();
46 return trackInfo;
47 }
48
PlayerTrackParse()49 PlayerTrackParse::PlayerTrackParse()
50 {
51 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
52 }
53
~PlayerTrackParse()54 PlayerTrackParse::~PlayerTrackParse()
55 {
56 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
57 }
58
GetVideoTrackInfo(std::vector<Format> & videoTrack)59 int32_t PlayerTrackParse::GetVideoTrackInfo(std::vector<Format> &videoTrack)
60 {
61 std::unique_lock<std::mutex> lock(trackInfoMutex_);
62 int32_t trackType;
63 for (auto &[pad, innerMeta] : trackInfos_) {
64 if (innerMeta.GetIntValue(INNER_META_KEY_TRACK_TYPE, trackType) && trackType == MediaType::MEDIA_TYPE_VID) {
65 Format outMeta;
66 ConvertToPlayerKeys(innerMeta, outMeta);
67 videoTrack.emplace_back(outMeta);
68 }
69 }
70 return MSERR_OK;
71 }
72
GetAudioTrackInfo(std::vector<Format> & audioTrack)73 int32_t PlayerTrackParse::GetAudioTrackInfo(std::vector<Format> &audioTrack)
74 {
75 std::unique_lock<std::mutex> lock(trackInfoMutex_);
76 int32_t trackType;
77 for (auto &[pad, innerMeta] : trackInfos_) {
78 if (innerMeta.GetIntValue(INNER_META_KEY_TRACK_TYPE, trackType) && trackType == MediaType::MEDIA_TYPE_AUD) {
79 Format outMeta;
80 ConvertToPlayerKeys(innerMeta, outMeta);
81 audioTrack.emplace_back(outMeta);
82 }
83 }
84 return MSERR_OK;
85 }
86
ConvertToPlayerKeys(const Format & innerMeta,Format & outMeta) const87 void PlayerTrackParse::ConvertToPlayerKeys(const Format &innerMeta, Format &outMeta) const
88 {
89 for (const auto &[innerKey, playerKey] : INNER_KEY_TO_PLAYER_KEY) {
90 if (!innerMeta.ContainKey(innerKey)) {
91 continue;
92 }
93
94 std::string strVal;
95 int32_t intVal;
96 FormatDataType type = innerMeta.GetValueType(innerKey);
97 switch (type) {
98 case FORMAT_TYPE_STRING:
99 innerMeta.GetStringValue(innerKey, strVal);
100 outMeta.PutStringValue(std::string(playerKey), strVal);
101 break;
102 case FORMAT_TYPE_INT32:
103 innerMeta.GetIntValue(innerKey, intVal);
104 outMeta.PutIntValue(std::string(playerKey), intVal);
105 break;
106 default:
107 break;
108 }
109 }
110 }
111
ProbeCallback(GstPad * pad,GstPadProbeInfo * info,gpointer userData)112 GstPadProbeReturn PlayerTrackParse::ProbeCallback(GstPad *pad, GstPadProbeInfo *info, gpointer userData)
113 {
114 if (pad == nullptr || info == nullptr || userData == nullptr) {
115 MEDIA_LOGE("param is invalid");
116 return GST_PAD_PROBE_OK;
117 }
118
119 auto playerTrackParse = reinterpret_cast<PlayerTrackParse *>(userData);
120 return playerTrackParse->GetTrackParse(pad, info);
121 }
122
GetTrackParse(GstPad * pad,GstPadProbeInfo * info)123 GstPadProbeReturn PlayerTrackParse::GetTrackParse(GstPad *pad, GstPadProbeInfo *info)
124 {
125 std::unique_lock<std::mutex> lock(trackInfoMutex_);
126 auto it = trackInfos_.find(pad);
127 CHECK_AND_RETURN_RET_LOG(it != trackInfos_.end(), GST_PAD_PROBE_OK,
128 "unrecognized pad %{public}s", PAD_NAME(pad));
129
130 if (static_cast<unsigned int>(info->type) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
131 GstEvent *event = gst_pad_probe_info_get_event(info);
132 CHECK_AND_RETURN_RET_LOG(event != nullptr, GST_PAD_PROBE_OK, "event is null");
133
134 if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
135 GstTagList *tagList = nullptr;
136 gst_event_parse_tag(event, &tagList);
137 CHECK_AND_RETURN_RET_LOG(tagList != nullptr, GST_PAD_PROBE_OK, "tags is nullptr")
138 MEDIA_LOGI("catch tags at pad %{public}s", PAD_NAME(pad));
139 GstMetaParser::ParseTagList(*tagList, it->second);
140 } else if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) {
141 GstCaps *caps = nullptr;
142 gst_event_parse_caps(event, &caps);
143 CHECK_AND_RETURN_RET_LOG(caps != nullptr, GST_PAD_PROBE_OK, "caps is nullptr")
144 MEDIA_LOGI("catch caps at pad %{public}s", PAD_NAME(pad));
145 GstMetaParser::ParseStreamCaps(*caps, it->second);
146 it->second.PutIntValue(INNER_META_KEY_TRACK_INDEX, trackcount_);
147 trackcount_++;
148 MEDIA_LOGD("GetTrackParse tarckcount %{public}d", trackcount_);
149 }
150 }
151
152 return GST_PAD_PROBE_OK;
153 }
154
AddProbeToPad(const GstElement * element,GstPad * pad)155 bool PlayerTrackParse::AddProbeToPad(const GstElement *element, GstPad *pad)
156 {
157 MEDIA_LOGD("AddProbeToPad element %{public}s, pad %{public}s", ELEM_NAME(element), PAD_NAME(pad));
158 {
159 std::unique_lock<std::mutex> lock(padProbeMutex_);
160 gulong probeId = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, ProbeCallback, this, nullptr);
161 if (probeId == 0) {
162 MEDIA_LOGE("add probe for %{public}s's pad %{public}s failed",
163 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)), PAD_NAME(pad));
164 return false;
165 }
166 (void)padProbes_.emplace(pad, probeId);
167 gst_object_ref(pad);
168 }
169 {
170 std::unique_lock<std::mutex> lock(trackInfoMutex_);
171 Format innerMeta;
172 (void)trackInfos_.emplace(pad, innerMeta);
173 }
174
175 return true;
176 }
177
AddProbeToPadList(const GstElement * element,GList & list)178 bool PlayerTrackParse::AddProbeToPadList(const GstElement *element, GList &list)
179 {
180 MEDIA_LOGD("AddProbeToPadList element %{public}s", ELEM_NAME(element));
181 for (GList *padNode = g_list_first(&list); padNode != nullptr; padNode = padNode->next) {
182 if (padNode->data == nullptr) {
183 continue;
184 }
185
186 GstPad *pad = reinterpret_cast<GstPad *>(padNode->data);
187 if (!AddProbeToPad(element, pad)) {
188 return false;
189 }
190 }
191
192 return true;
193 }
194
OnPadAddedCb(const GstElement * element,GstPad * pad,gpointer userData)195 void PlayerTrackParse::OnPadAddedCb(const GstElement *element, GstPad *pad, gpointer userData)
196 {
197 if (element == nullptr || pad == nullptr || userData == nullptr) {
198 MEDIA_LOGE("param is nullptr");
199 return;
200 }
201
202 auto playerTrackParse = reinterpret_cast<PlayerTrackParse *>(userData);
203 (void)playerTrackParse->AddProbeToPad(element, pad);
204 }
205
SetDemuxerElementFind(bool isFind)206 void PlayerTrackParse::SetDemuxerElementFind(bool isFind)
207 {
208 demuxerElementFind_ = isFind;
209 }
210
GetDemuxerElementFind() const211 bool PlayerTrackParse::GetDemuxerElementFind() const
212 {
213 return demuxerElementFind_;
214 }
215
SetUpDemuxerElementCb(GstElement & elem)216 void PlayerTrackParse::SetUpDemuxerElementCb(GstElement &elem)
217 {
218 MEDIA_LOGD("SetUpDemuxerElementCb elem %{public}s", ELEM_NAME(&elem));
219 if (!AddProbeToPadList(&elem, *elem.srcpads)) {
220 return;
221 }
222 {
223 std::unique_lock<std::mutex> lock(signalIdMutex_);
224 gulong signalId = g_signal_connect(&elem, "pad-added", G_CALLBACK(PlayerTrackParse::OnPadAddedCb), this);
225 CHECK_AND_RETURN_LOG(signalId != 0, "listen to pad-added failed");
226 (void)signalIds_.emplace_back(SignalInfo { &elem, signalId });
227 }
228 }
229
SetUpParseElementCb(GstElement & elem)230 void PlayerTrackParse::SetUpParseElementCb(GstElement &elem)
231 {
232 MEDIA_LOGD("SetUpParseElementCb elem %{public}s", ELEM_NAME(&elem));
233 (void)AddProbeToPadList(&elem, *elem.srcpads);
234 }
235
Stop()236 void PlayerTrackParse::Stop()
237 {
238 MEDIA_LOGD("Stop");
239 {
240 std::unique_lock<std::mutex> lock(trackInfoMutex_);
241 trackInfos_.clear();
242 }
243 {
244 std::unique_lock<std::mutex> lock(padProbeMutex_);
245 // PlayerTrackParse::ProbeCallback
246 for (auto &[pad, probeId] : padProbes_) {
247 MEDIA_LOGD("remove_probe pad %{public}s", PAD_NAME(pad));
248 gst_pad_remove_probe(pad, probeId);
249 gst_object_unref(pad);
250 }
251 padProbes_.clear();
252 }
253 {
254 std::unique_lock<std::mutex> lock(signalIdMutex_);
255 // PlayerTrackParse::OnPadAddedCb
256 for (auto &item : signalIds_) {
257 g_signal_handler_disconnect(item.element, item.signalId);
258 }
259 signalIds_.clear();
260 }
261 }
262 }
263 }
264