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 #include "scope_guard.h"
24
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayerTrackParse"};
27 }
28
29 namespace OHOS {
30 namespace Media {
31 inline constexpr std::string_view INNER_META_KEY_TRACK_INNER_INDEX = "track_inner_index";
32
33 static const std::unordered_map<std::string_view, std::string_view> INNER_KEY_TO_PLAYER_KEY = {
34 { INNER_META_KEY_BITRATE, PlayerKeys::PLAYER_BITRATE },
35 { INNER_META_KEY_CHANNEL_COUNT, PlayerKeys::PLAYER_CHANNELS },
36 { INNER_META_KEY_FRAMERATE, PlayerKeys::PLAYER_FRAMERATE },
37 { INNER_META_KEY_VIDEO_HEIGHT, PlayerKeys::PLAYER_HEIGHT },
38 { INNER_META_KEY_LANGUAGE, PlayerKeys::PLAYER_LANGUGAE },
39 { INNER_META_KEY_MIME_TYPE, PlayerKeys::PLAYER_MIME },
40 { INNER_META_KEY_SAMPLE_RATE, PlayerKeys::PLAYER_SAMPLE_RATE },
41 { INNER_META_KEY_TRACK_INDEX, PlayerKeys::PLAYER_TRACK_INDEX },
42 { INNER_META_KEY_TRACK_TYPE, PlayerKeys::PLAYER_TRACK_TYPE },
43 { INNER_META_KEY_VIDEO_WIDTH, PlayerKeys::PLAYER_WIDTH },
44 { INNER_META_KEY_TRACK_INNER_INDEX, INNER_META_KEY_TRACK_INNER_INDEX },
45 };
46
Create()47 std::shared_ptr<PlayerTrackParse> PlayerTrackParse::Create()
48 {
49 std::shared_ptr<PlayerTrackParse> trackInfo = std::make_shared<PlayerTrackParse>();
50 return trackInfo;
51 }
52
PlayerTrackParse()53 PlayerTrackParse::PlayerTrackParse()
54 {
55 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
56 }
57
~PlayerTrackParse()58 PlayerTrackParse::~PlayerTrackParse()
59 {
60 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
61 }
62
OnElementSetup(GstElement & elem)63 void PlayerTrackParse::OnElementSetup(GstElement &elem)
64 {
65 CHECK_AND_RETURN_LOG(isStopping_.load() == false, "playbin is stopping");
66 const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
67 CHECK_AND_RETURN_LOG(metadata != nullptr, "gst_element_get_metadata return nullptr");
68 std::string elementName(GST_ELEMENT_NAME(&elem));
69
70 std::string metaStr(metadata);
71 if (metaStr.find("Codec/Demuxer") != std::string::npos && elementName.find("hlsdemux") == std::string::npos) {
72 // Collect trackinfo information
73 std::unique_lock<std::mutex> lock(trackInfoMutex_);
74 DemuxInfo demux(&elem);
75 trackVec_.push_back(demux);
76 lock.unlock();
77 SetUpDemuxerElementCb(elem);
78 }
79
80 if (metaStr.find("Codec/Parser") != std::string::npos) {
81 // HLS stream demux has no width and height data, and requires prase as a supplement
82 SetUpDemuxerElementCb(elem);
83 }
84
85 if (elementName.find("inputselector") != std::string::npos) {
86 // Detect resolution switching events
87 std::unique_lock<std::mutex> lock(trackInfoMutex_);
88 InputSelectInfo info;
89 inputSelectMap_.insert(std::pair<GstElement *, InputSelectInfo>(&elem, info));
90 lock.unlock();
91 SetUpInputSelectElementCb(elem);
92 }
93 }
94
OnElementUnSetup(GstElement & elem)95 void PlayerTrackParse::OnElementUnSetup(GstElement &elem)
96 {
97 const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
98 CHECK_AND_RETURN_LOG(metadata != nullptr, "gst_element_get_metadata return nullptr");
99 std::string elementName(GST_ELEMENT_NAME(&elem));
100 std::string metaStr(metadata);
101
102 std::unique_lock<std::mutex> lock(trackInfoMutex_);
103 if (metaStr.find("Codec/Demuxer") != std::string::npos) {
104 MEDIA_LOGI("UnSetUp Demuxer elem %{public}s", ELEM_NAME(&elem));
105 for (auto it = trackVec_.begin(); it != trackVec_.end(); it++) {
106 if (it->demux == &elem) {
107 trackVec_.erase(it);
108 MEDIA_LOGI("remove demux from trackVec 0x%{public}06" PRIXPTR, FAKE_POINTER(&elem));
109 break;
110 }
111 }
112 }
113
114 if (elementName.find("inputselector") != std::string::npos) {
115 MEDIA_LOGI("UnSetUp inputselector elem %{public}s", ELEM_NAME(&elem));
116
117 auto it = inputSelectMap_.find(&elem);
118 if (it != inputSelectMap_.end()) {
119 inputSelectMap_.erase(it);
120 }
121
122 if (inputSelectMap_.empty()) {
123 findTrackInfo_ = false;
124 MEDIA_LOGI("Remove all inputselect plugins");
125 }
126 }
127
128 RemoveSignalIds(&elem);
129 }
130
SetUpInputSelectElementCb(GstElement & elem)131 void PlayerTrackParse::SetUpInputSelectElementCb(GstElement &elem)
132 {
133 MEDIA_LOGD("SetUpInputSelectElementCb elem %{public}s", ELEM_NAME(&elem));
134 {
135 std::unique_lock<std::mutex> lock(signalIdMutex_);
136 gulong signalId = g_signal_connect(&elem, "pad-added",
137 G_CALLBACK(PlayerTrackParse::OnInputSelectPadAddedCb), this);
138 CHECK_AND_RETURN_LOG(signalId != 0, "listen to pad-added failed");
139 AddSignalIds(&elem, signalId);
140 }
141 }
142
OnInputSelectPadAddedCb(const GstElement * element,GstPad * pad,gpointer userData)143 void PlayerTrackParse::OnInputSelectPadAddedCb(const GstElement *element, GstPad *pad, gpointer userData)
144 {
145 CHECK_AND_RETURN_LOG(element != nullptr && pad != nullptr && userData != nullptr, "param is nullptr");
146
147 auto playerTrackParse = reinterpret_cast<PlayerTrackParse *>(userData);
148 (void)playerTrackParse->InputSelectAddProbeToPad(element, pad);
149 }
150
InputSelectAddProbeToPad(const GstElement * element,GstPad * pad)151 bool PlayerTrackParse::InputSelectAddProbeToPad(const GstElement *element, GstPad *pad)
152 {
153 {
154 std::unique_lock<std::mutex> lock(trackInfoMutex_);
155 auto it = inputSelectMap_.find(const_cast<GstElement *>(element));
156 CHECK_AND_RETURN_RET_LOG(it != inputSelectMap_.end(), false, "Unregistered elements");
157 it->second.padIndexMap[pad] = it->second.padCount;
158 it->second.padCount++;
159 MEDIA_LOGD("AddProbeToPad element %{public}s, pad %{public}s, count %{public}d",
160 ELEM_NAME(element), PAD_NAME(pad), it->second.padCount);
161 }
162
163 std::unique_lock<std::mutex> lock(padProbeMutex_);
164 gulong probeId = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
165 InputSelectProbeCallback, this, nullptr);
166 CHECK_AND_RETURN_RET_LOG(probeId != 0, false, "add probe for %{public}s's pad %{public}s failed",
167 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)), PAD_NAME(pad));
168 (void)padProbes_.emplace(pad, probeId);
169 gst_object_ref(pad);
170 return true;
171 }
172
InputSelectProbeCallback(GstPad * pad,GstPadProbeInfo * info,gpointer userData)173 GstPadProbeReturn PlayerTrackParse::InputSelectProbeCallback(GstPad *pad, GstPadProbeInfo *info, gpointer userData)
174 {
175 CHECK_AND_RETURN_RET_LOG(pad != nullptr && info != nullptr && userData != nullptr,
176 GST_PAD_PROBE_OK, "param is nullptr");
177
178 auto playerTrackParse = reinterpret_cast<PlayerTrackParse *>(userData);
179 return playerTrackParse->GetUsedDemux(pad, info);
180 }
181
GetUsedDemux(GstPad * pad,GstPadProbeInfo * info)182 GstPadProbeReturn PlayerTrackParse::GetUsedDemux(GstPad *pad, GstPadProbeInfo *info)
183 {
184 (void)pad;
185 CHECK_AND_RETURN_RET((static_cast<unsigned int>(info->type) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) != 0,
186 GST_PAD_PROBE_OK);
187
188 GstEvent *event = gst_pad_probe_info_get_event(info);
189 CHECK_AND_RETURN_RET_LOG(event != nullptr, GST_PAD_PROBE_OK, "event is null");
190 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START) {
191 return GST_PAD_PROBE_OK;
192 }
193
194 const gchar *current_stream_id;
195 gst_event_parse_stream_start (event, ¤t_stream_id);
196 CHECK_AND_RETURN_RET_LOG(current_stream_id != nullptr, GST_PAD_PROBE_OK, "current_stream_id is nullptr");
197
198 std::unique_lock<std::mutex> lock(trackInfoMutex_);
199 for (int32_t i = 0; i < static_cast<int32_t>(trackVec_.size()); i++) {
200 for (auto padIt = trackVec_[i].trackInfos.begin(); padIt != trackVec_[i].trackInfos.end(); padIt++) {
201 gchar *stream_id = gst_pad_get_stream_id(padIt->first);
202 CHECK_AND_CONTINUE(stream_id != nullptr && current_stream_id != nullptr);
203 if (strcmp(current_stream_id, stream_id) == 0) {
204 findTrackInfo_ = true;
205 trackVec_[i].inUse = true;
206 int32_t index = GetInputSelectPadIndex(pad);
207 padIt->second.PutIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), index);
208 MEDIA_LOGD("Matched to pad:0x%{public}06" PRIXPTR ", index:%{public}d, streamid:%{public}s",
209 FAKE_POINTER(padIt->first), index, stream_id);
210 UpdateTrackInfo();
211 g_free (stream_id);
212 return GST_PAD_PROBE_OK;
213 }
214 g_free (stream_id);
215 }
216 }
217
218 return GST_PAD_PROBE_OK;
219 }
220
GetInputSelectPadIndex(GstPad * pad)221 int32_t PlayerTrackParse::GetInputSelectPadIndex(GstPad *pad)
222 {
223 CHECK_AND_RETURN_RET(pad != nullptr, -1);
224 int32_t index = -1;
225 for (auto inputIt = inputSelectMap_.begin(); inputIt != inputSelectMap_.end(); inputIt++) {
226 auto inputPadIt = inputIt ->second.padIndexMap.find(pad);
227 if (inputPadIt != inputIt ->second.padIndexMap.end()) {
228 index = inputPadIt->second;
229 break;
230 }
231 }
232 return index;
233 }
234
IsSameStreamId(GstPad * padA,GstPad * padB)235 bool PlayerTrackParse::IsSameStreamId(GstPad *padA, GstPad *padB)
236 {
237 gchar *streamIdA = gst_pad_get_stream_id(padA);
238 CHECK_AND_RETURN_RET_LOG(streamIdA != nullptr, false, "streamIdA is nullptr");
239 ON_SCOPE_EXIT(0) { g_free(streamIdA); };
240 gchar *streamIdB = gst_pad_get_stream_id(padB);
241 CHECK_AND_RETURN_RET_LOG(streamIdB != nullptr, false, "streamIdB is nullptr");
242 CANCEL_SCOPE_EXIT_GUARD(0);
243
244 bool ret = (strcmp(streamIdA, streamIdB) == 0);
245 g_free(streamIdA);
246 g_free(streamIdB);
247 return ret;
248 }
249
HasSameStreamIdInDemux(GstPad * pad)250 bool PlayerTrackParse::HasSameStreamIdInDemux(GstPad *pad)
251 {
252 for (int32_t i = 0; i < static_cast<int32_t>(trackVec_.size()); i++) {
253 for (auto padIt = trackVec_[i].trackInfos.begin(); padIt != trackVec_[i].trackInfos.end(); padIt++) {
254 CHECK_AND_RETURN_RET(!IsSameStreamId(pad, padIt->first), true);
255 }
256 }
257
258 return false;
259 }
260
GetTrackInfo(int32_t index,int32_t & innerIndex,int32_t & trackType)261 int32_t PlayerTrackParse::GetTrackInfo(int32_t index, int32_t &innerIndex, int32_t &trackType)
262 {
263 std::unique_lock<std::mutex> lock(trackInfoMutex_);
264 CHECK_AND_RETURN_RET_LOG(findTrackInfo_, MSERR_INVALID_OPERATION, "trackinfo not found");
265 CHECK_AND_RETURN_RET_LOG(index >= 0, MSERR_INVALID_VAL, "Invalid index %{public}d", index);
266
267 StartUpdateTrackInfo();
268
269 for (int32_t i = 0; i < static_cast<int32_t>(videoTracks_.size()); i++) {
270 int32_t trackIndex = -1;
271 videoTracks_[i].GetIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), trackIndex);
272 if (trackIndex == index) {
273 trackType = MediaType::MEDIA_TYPE_VID;
274 videoTracks_[i].GetIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), innerIndex);
275 MEDIA_LOGI("index:0x%{public}d inner:0x%{public}d Type:0x%{public}d", index, innerIndex, trackType);
276 return MSERR_OK;
277 }
278 }
279
280 for (int32_t i = 0; i < static_cast<int32_t>(audioTracks_.size()); i++) {
281 int32_t trackIndex = -1;
282 audioTracks_[i].GetIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), trackIndex);
283 if (trackIndex == index) {
284 trackType = MediaType::MEDIA_TYPE_AUD;
285 audioTracks_[i].GetIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), innerIndex);
286 MEDIA_LOGI("index:0x%{public}d inner:0x%{public}d Type:0x%{public}d", index, innerIndex, trackType);
287 return MSERR_OK;
288 }
289 }
290
291 for (int32_t i = 0; i < static_cast<int32_t>(subtitleTracks_.size()); i++) {
292 int32_t trackIndex = -1;
293 subtitleTracks_[i].GetIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), trackIndex);
294 if (trackIndex == index) {
295 trackType = MediaType::MEDIA_TYPE_SUBTITLE;
296 subtitleTracks_[i].GetIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), innerIndex);
297 MEDIA_LOGI("index:0x%{public}d inner:0x%{public}d Type:0x%{public}d", index, innerIndex, trackType);
298 return MSERR_OK;
299 }
300 }
301
302 return MSERR_INVALID_VAL;
303 }
304
GetTrackIndex(int32_t innerIndex,int32_t trackType,int32_t & index)305 int32_t PlayerTrackParse::GetTrackIndex(int32_t innerIndex, int32_t trackType, int32_t &index)
306 {
307 std::unique_lock<std::mutex> lock(trackInfoMutex_);
308 CHECK_AND_RETURN_RET_LOG(findTrackInfo_, MSERR_INVALID_OPERATION, "trackinfo not found");
309 CHECK_AND_RETURN_RET_LOG(trackType >= MediaType::MEDIA_TYPE_AUD && trackType <= MediaType::MEDIA_TYPE_SUBTITLE,
310 MSERR_INVALID_VAL, "Invalid trackType %{public}d", trackType);
311 CHECK_AND_RETURN_RET_LOG(innerIndex >= 0, MSERR_INVALID_VAL, "Invalid innerIndex %{public}d", innerIndex);
312
313 StartUpdateTrackInfo();
314
315 if (trackType == MediaType::MEDIA_TYPE_AUD) {
316 for (int32_t i = 0; i < static_cast<int32_t>(audioTracks_.size()); i++) {
317 int32_t trackInnerIndex = -1;
318 audioTracks_[i].GetIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), trackInnerIndex);
319 if (trackInnerIndex == innerIndex) {
320 audioTracks_[i].GetIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
321 MEDIA_LOGI("inner:0x%{public}d Type:0x%{public}d index:0x%{public}d", innerIndex, trackType, index);
322 return MSERR_OK;
323 }
324 }
325 } else if (trackType == MediaType::MEDIA_TYPE_VID) {
326 for (int32_t i = 0; i < static_cast<int32_t>(videoTracks_.size()); i++) {
327 int32_t trackInnerIndex = -1;
328 videoTracks_[i].GetIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), trackInnerIndex);
329 if (trackInnerIndex == innerIndex) {
330 videoTracks_[i].GetIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
331 MEDIA_LOGI("inner:0x%{public}d Type:0x%{public}d index:0x%{public}d", innerIndex, trackType, index);
332 return MSERR_OK;
333 }
334 }
335 } else {
336 index = static_cast<size_t>(innerIndex) + videoTracks_.size() + audioTracks_.size();
337 MEDIA_LOGI("inner:0x%{public}d Type:0x%{public}d index:0x%{public}d", innerIndex, trackType, index);
338 return MSERR_OK;
339 }
340
341 return MSERR_INVALID_VAL;
342 }
343
StartUpdateTrackInfo()344 void PlayerTrackParse::StartUpdateTrackInfo()
345 {
346 if (!updateTrackInfo_) {
347 updateTrackInfo_ = true;
348 UpdateTrackInfo();
349 }
350 }
351
UpdateTrackInfo()352 void PlayerTrackParse::UpdateTrackInfo()
353 {
354 if (!updateTrackInfo_) {
355 return;
356 }
357 CHECK_AND_RETURN(findTrackInfo_);
358 videoTracks_.clear();
359 audioTracks_.clear();
360 subtitleTracks_.clear();
361
362 int32_t index;
363 int32_t baseIndex = 0;
364 std::map<int32_t, Format> tracks;
365 for (int32_t i = 0; i < static_cast<int32_t>(trackVec_.size()); i++) {
366 if (!trackVec_[i].inUse) {
367 continue;
368 }
369 for (auto &[pad, innerMeta] : trackVec_[i].trackInfos) {
370 // Sort trackinfo by index
371 innerMeta.GetIntValue(std::string(INNER_META_KEY_TRACK_INDEX), index);
372 (void)tracks.emplace(index + baseIndex, innerMeta);
373 }
374 baseIndex += trackVec_[i].trackcount;
375 }
376
377 int32_t trackType = MediaType::MEDIA_TYPE_AUD;
378 for (auto &[ind, innerMeta] : tracks) {
379 Format outMeta;
380 innerMeta.GetIntValue(INNER_META_KEY_TRACK_TYPE, trackType);
381 ConvertToPlayerKeys(innerMeta, outMeta);
382 outMeta.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), ind);
383 if (trackType == MediaType::MEDIA_TYPE_VID) {
384 videoTracks_.emplace_back(outMeta);
385 } else if (trackType == MediaType::MEDIA_TYPE_AUD) {
386 audioTracks_.emplace_back(outMeta);
387 } else if (trackType == MediaType::MEDIA_TYPE_SUBTITLE) {
388 subtitleTracks_.emplace_back(outMeta);
389 }
390 }
391 return;
392 }
393
GetVideoTrackInfo(std::vector<Format> & videoTrack)394 int32_t PlayerTrackParse::GetVideoTrackInfo(std::vector<Format> &videoTrack)
395 {
396 std::unique_lock<std::mutex> lock(trackInfoMutex_);
397 CHECK_AND_RETURN_RET_LOG(findTrackInfo_, MSERR_INVALID_OPERATION, "trackinfo not found");
398 StartUpdateTrackInfo();
399 videoTrack.assign(videoTracks_.begin(), videoTracks_.end());
400 for (int32_t i = 0; i < static_cast<int32_t>(videoTracks_.size()); i++) {
401 videoTrack[i].RemoveKey(std::string(INNER_META_KEY_TRACK_INNER_INDEX));
402 }
403 return MSERR_OK;
404 }
405
GetAudioTrackInfo(std::vector<Format> & audioTrack)406 int32_t PlayerTrackParse::GetAudioTrackInfo(std::vector<Format> &audioTrack)
407 {
408 std::unique_lock<std::mutex> lock(trackInfoMutex_);
409 CHECK_AND_RETURN_RET_LOG(findTrackInfo_, MSERR_INVALID_OPERATION, "trackinfo not found");
410 StartUpdateTrackInfo();
411 audioTrack.assign(audioTracks_.begin(), audioTracks_.end());
412 for (int32_t i = 0; i < static_cast<int32_t>(audioTrack.size()); i++) {
413 audioTrack[i].RemoveKey(std::string(INNER_META_KEY_TRACK_INNER_INDEX));
414 }
415 return MSERR_OK;
416 }
417
GetSubtitleTrackInfo(std::vector<Format> & subtitleTrack)418 int32_t PlayerTrackParse::GetSubtitleTrackInfo(std::vector<Format> &subtitleTrack)
419 {
420 std::unique_lock<std::mutex> lock(trackInfoMutex_);
421 CHECK_AND_RETURN_RET_LOG(findTrackInfo_, MSERR_INVALID_OPERATION, "trackinfo not found");
422 StartUpdateTrackInfo();
423 subtitleTrack.assign(subtitleTracks_.begin(), subtitleTracks_.end());
424 for (int32_t i = 0; i < static_cast<int32_t>(subtitleTrack.size()); i++) {
425 subtitleTrack[i].RemoveKey(std::string(INNER_META_KEY_TRACK_INNER_INDEX));
426 }
427 return MSERR_OK;
428 }
429
ConvertToPlayerKeys(const Format & innerMeta,Format & outMeta) const430 void PlayerTrackParse::ConvertToPlayerKeys(const Format &innerMeta, Format &outMeta) const
431 {
432 for (const auto &[innerKey, playerKey] : INNER_KEY_TO_PLAYER_KEY) {
433 if (!innerMeta.ContainKey(innerKey)) {
434 continue;
435 }
436
437 std::string strVal;
438 int32_t intVal;
439 double douVal;
440 FormatDataType type = innerMeta.GetValueType(innerKey);
441 switch (type) {
442 case FORMAT_TYPE_STRING:
443 innerMeta.GetStringValue(innerKey, strVal);
444 outMeta.PutStringValue(std::string(playerKey), strVal);
445 break;
446 case FORMAT_TYPE_INT32:
447 innerMeta.GetIntValue(innerKey, intVal);
448 outMeta.PutIntValue(std::string(playerKey), intVal);
449 break;
450 case FORMAT_TYPE_DOUBLE:
451 innerMeta.GetDoubleValue(innerKey, douVal);
452 outMeta.PutDoubleValue(std::string(playerKey), douVal);
453 break;
454 default:
455 break;
456 }
457 }
458 }
459
ProbeCallback(GstPad * pad,GstPadProbeInfo * info,gpointer userData)460 GstPadProbeReturn PlayerTrackParse::ProbeCallback(GstPad *pad, GstPadProbeInfo *info, gpointer userData)
461 {
462 CHECK_AND_RETURN_RET_LOG(pad != nullptr && info != nullptr && userData != nullptr,
463 GST_PAD_PROBE_OK, "param is invalid");
464
465 auto playerTrackParse = reinterpret_cast<PlayerTrackParse *>(userData);
466 return playerTrackParse->GetTrackParse(pad, info);
467 }
468
GetTrackParse(GstPad * pad,GstPadProbeInfo * info)469 GstPadProbeReturn PlayerTrackParse::GetTrackParse(GstPad *pad, GstPadProbeInfo *info)
470 {
471 std::unique_lock<std::mutex> lock(trackInfoMutex_);
472 bool isDemuxPad = (parsePadSet_.count(pad) == 0);
473 for (int32_t i = 0; i < static_cast<int32_t>(trackVec_.size()); i++) {
474 if (isDemuxPad) {
475 auto padIt = trackVec_[i].trackInfos.find(pad);
476 if (padIt != trackVec_[i].trackInfos.end()) {
477 return ParseTrackInfo(pad, info, padIt->second);
478 }
479 continue;
480 }
481
482 for (auto padIt = trackVec_[i].trackInfos.begin(); padIt != trackVec_[i].trackInfos.end(); padIt++) {
483 if (IsSameStreamId(pad, padIt->first)) {
484 return ParseTrackInfo(pad, info, padIt->second);
485 }
486 }
487 }
488 return GST_PAD_PROBE_OK;
489 }
490
ParseTrackInfo(GstPad * pad,GstPadProbeInfo * info,Format & format)491 GstPadProbeReturn PlayerTrackParse::ParseTrackInfo(GstPad *pad, GstPadProbeInfo *info, Format &format)
492 {
493 if (static_cast<unsigned int>(info->type) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
494 GstEvent *event = gst_pad_probe_info_get_event(info);
495 CHECK_AND_RETURN_RET_LOG(event != nullptr, GST_PAD_PROBE_OK, "event is null");
496
497 if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
498 GstTagList *tagList = nullptr;
499 gst_event_parse_tag(event, &tagList);
500 CHECK_AND_RETURN_RET_LOG(tagList != nullptr, GST_PAD_PROBE_OK, "tags is nullptr");
501 GstMetaParser::ParseTagList(*tagList, format);
502 MEDIA_LOGI("catch tags at pad %{public}s:0x%{public}06" PRIXPTR, PAD_NAME(pad), FAKE_POINTER(pad));
503 (void)UpdateTrackInfo();
504 } else if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) {
505 GstCaps *caps = nullptr;
506 gst_event_parse_caps(event, &caps);
507 CHECK_AND_RETURN_RET_LOG(caps != nullptr, GST_PAD_PROBE_OK, "caps is nullptr");
508 GstMetaParser::ParseStreamCaps(*caps, format);
509 MEDIA_LOGI("catch caps at pad %{public}s:0x%{public}06" PRIXPTR, PAD_NAME(pad), FAKE_POINTER(pad));
510 (void)UpdateTrackInfo();
511 }
512 }
513 return GST_PAD_PROBE_OK;
514 }
515
ParseSubtitlePadCaps(const GstElement * element,GstPad * pad,int32_t index,Format & innerMeta)516 void PlayerTrackParse::ParseSubtitlePadCaps(const GstElement *element, GstPad *pad, int32_t index, Format &innerMeta)
517 {
518 GstCaps *caps = gst_pad_query_caps(pad, nullptr);
519 GstMetaParser::ParseStreamCaps(*caps, innerMeta);
520 trackVec_[index].inUse = true;
521 (void)trackVec_[index].trackInfos.emplace(pad, innerMeta);
522 UpdateTrackInfo();
523 MEDIA_LOGI("subtitle parse:0x%{public}06" PRIXPTR " trackcount:0x%{public}d pad:0x%{public}06" PRIXPTR,
524 FAKE_POINTER(element), trackVec_[index].trackcount, FAKE_POINTER(pad));
525 }
526
AddProbeToPad(const GstElement * element,GstPad * pad)527 bool PlayerTrackParse::AddProbeToPad(const GstElement *element, GstPad *pad)
528 {
529 MEDIA_LOGD("AddProbeToPad element %{public}s, pad %{public}s", ELEM_NAME(element), PAD_NAME(pad));
530 {
531 std::unique_lock<std::mutex> lock(padProbeMutex_);
532 gulong probeId = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, ProbeCallback, this, nullptr);
533 CHECK_AND_RETURN_RET_LOG(probeId != 0, false,
534 "add probe for %{public}s's pad %{public}s failed", GST_ELEMENT_NAME(GST_PAD_PARENT(pad)), PAD_NAME(pad));
535 (void)padProbes_.emplace(pad, probeId);
536 gst_object_ref(pad);
537 }
538 {
539 std::unique_lock<std::mutex> lock(trackInfoMutex_);
540
541 const gchar *metadata = gst_element_get_metadata(const_cast<GstElement *>(element),
542 GST_ELEMENT_METADATA_KLASS);
543 CHECK_AND_RETURN_RET_LOG(metadata != nullptr, true, "gst_element_get_metadata return nullptr");
544 std::string metaStr(metadata);
545 if (metaStr.find("Codec/Parser/Subtitle") != std::string::npos && !HasSameStreamIdInDemux(pad)) {
546 MEDIA_LOGD("external subtitle parser, handle it as demux");
547 DemuxInfo demux(const_cast<GstElement *>(element));
548 trackVec_.push_back(demux);
549 } else if (metaStr.find("Codec/Parser") != std::string::npos) {
550 parsePadSet_.insert(pad);
551 MEDIA_LOGI("Parser pad:0x%{public}06" PRIXPTR, FAKE_POINTER(pad));
552 return true;
553 }
554
555 for (int32_t i = 0; i < static_cast<int32_t>(trackVec_.size()); i++) {
556 if (trackVec_[i].demux != element) {
557 continue;
558 }
559
560 Format innerMeta;
561 innerMeta.PutIntValue(std::string(INNER_META_KEY_TRACK_INNER_INDEX), -1);
562 innerMeta.PutIntValue(std::string(INNER_META_KEY_TRACK_INDEX), trackVec_[i].trackcount);
563 trackVec_[i].trackcount++;
564 if (metaStr.find("Codec/Parser/Subtitle") != std::string::npos && !HasSameStreamIdInDemux(pad)) {
565 ParseSubtitlePadCaps(element, pad, i, innerMeta);
566 continue;
567 }
568 (void)trackVec_[i].trackInfos.emplace(pad, innerMeta);
569 MEDIA_LOGI("demux:0x%{public}06" PRIXPTR " trackcount:0x%{public}d pad:0x%{public}06" PRIXPTR,
570 FAKE_POINTER(element), trackVec_[i].trackcount, FAKE_POINTER(pad));
571 }
572 }
573
574 return true;
575 }
576
AddProbeToPadList(GstElement * element,GList & list)577 bool PlayerTrackParse::AddProbeToPadList(GstElement *element, GList &list)
578 {
579 MEDIA_LOGD("AddProbeToPadList element %{public}s", ELEM_NAME(element));
580 for (GList *padNode = g_list_first(&list); padNode != nullptr; padNode = padNode->next) {
581 CHECK_AND_CONTINUE(padNode->data != nullptr);
582
583 GstPad *pad = reinterpret_cast<GstPad *>(padNode->data);
584 CHECK_AND_RETURN_RET(AddProbeToPad(element, pad), false);
585 }
586
587 return true;
588 }
589
OnPadAddedCb(const GstElement * element,GstPad * pad,gpointer userData)590 void PlayerTrackParse::OnPadAddedCb(const GstElement *element, GstPad *pad, gpointer userData)
591 {
592 CHECK_AND_RETURN_LOG(element != nullptr && pad != nullptr && userData != nullptr, "param is nullptr");
593
594 auto playerTrackParse = reinterpret_cast<PlayerTrackParse *>(userData);
595 (void)playerTrackParse->AddProbeToPad(element, pad);
596 }
597
FindTrackInfo()598 bool PlayerTrackParse::FindTrackInfo()
599 {
600 std::unique_lock<std::mutex> lock(trackInfoMutex_);
601 return findTrackInfo_;
602 }
603
SetUpDemuxerElementCb(GstElement & elem)604 void PlayerTrackParse::SetUpDemuxerElementCb(GstElement &elem)
605 {
606 MEDIA_LOGD("SetUpDemuxerElementCb elem %{public}s", ELEM_NAME(&elem));
607 CHECK_AND_RETURN(AddProbeToPadList(&elem, *elem.srcpads));
608 {
609 std::unique_lock<std::mutex> lock(signalIdMutex_);
610 gulong signalId = g_signal_connect(&elem, "pad-added", G_CALLBACK(PlayerTrackParse::OnPadAddedCb), this);
611 CHECK_AND_RETURN_LOG(signalId != 0, "listen to pad-added failed");
612 AddSignalIds(&elem, signalId);
613 }
614 }
615
Stop()616 void PlayerTrackParse::Stop()
617 {
618 MEDIA_LOGD("Stop");
619 isStopping_ = true;
620 {
621 std::unique_lock<std::mutex> lock(trackInfoMutex_);
622 videoTracks_.clear();
623 audioTracks_.clear();
624 updateTrackInfo_ = false;
625 findTrackInfo_ = false;
626 inputSelectMap_.clear();
627 parsePadSet_.clear();
628 trackVec_.clear();
629 }
630 {
631 std::unique_lock<std::mutex> lock(padProbeMutex_);
632 // PlayerTrackParse::ProbeCallback
633 for (auto &[pad, probeId] : padProbes_) {
634 MEDIA_LOGD("remove_probe pad %{public}s", PAD_NAME(pad));
635 gst_pad_remove_probe(pad, probeId);
636 gst_object_unref(pad);
637 }
638 padProbes_.clear();
639 }
640 {
641 std::unique_lock<std::mutex> lock(signalIdMutex_);
642 // PlayerTrackParse::OnPadAddedCb
643 for (auto &item : signalIds_) {
644 for (auto id : item.second) {
645 g_signal_handler_disconnect(item.first, id);
646 }
647 }
648 signalIds_.clear();
649 }
650 }
651 }
652 }
653