• 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 "avmeta_elem_meta_collector.h"
17 #include <string_view>
18 #include <limits>
19 #include "avmetadatahelper.h"
20 #include "avsharedmemorybase.h"
21 #include "av_common.h"
22 #include "gst_meta_parser.h"
23 #include "gst_utils.h"
24 #include "media_errors.h"
25 #include "media_log.h"
26 #include "securec.h"
27 
28 namespace {
29     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMetaElemCollector"};
30 }
31 
32 namespace OHOS {
33 namespace Media {
34 #define AVMETA_KEY_TO_X_MAP_ITEM(key, innerKey) { key, innerKey }
35 
36 static const std::unordered_map<int32_t, std::string_view> AVMETA_KEY_TO_X_MAP = {
37     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_ALBUM, INNER_META_KEY_ALBUM),
38     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_ALBUM_ARTIST, INNER_META_KEY_ALBUM_ARTIST),
39     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_ARTIST, INNER_META_KEY_ARTIST),
40     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_AUTHOR, INNER_META_KEY_AUTHOR),
41     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_COMPOSER, INNER_META_KEY_COMPOSER),
42     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_DATE_TIME, INNER_META_KEY_DATE_TIME),
43     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_DATE_TIME_FORMAT, ""),
44     /**
45      * The most of gst plugins don't send the GST_TAG_DURATION, we obtain this
46      * information from duration query.
47      */
48     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_DURATION, ""),
49     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_GENRE, INNER_META_KEY_GENRE),
50     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_HAS_AUDIO, ""),
51     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_HAS_VIDEO, ""),
52     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_MIME_TYPE, INNER_META_KEY_MIME_TYPE),
53     /**
54      * The GST_TAG_TRACK_COUNT does not means the actual track count, we obtain
55      * this information from pads count.
56      */
57     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_NUM_TRACKS, ""),
58     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_SAMPLE_RATE, INNER_META_KEY_SAMPLE_RATE),
59     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_TITLE, INNER_META_KEY_TITLE),
60     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_VIDEO_HEIGHT, INNER_META_KEY_VIDEO_HEIGHT),
61     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_VIDEO_WIDTH, INNER_META_KEY_VIDEO_WIDTH),
62     AVMETA_KEY_TO_X_MAP_ITEM(AV_KEY_VIDEO_ORIENTATION, INNER_META_KEY_VIDEO_ORIENTATION),
63 };
64 
FormatDataTime(std::string & dataTime)65 std::string FormatDataTime(std::string &dataTime)
66 {
67     std::string::size_type position = dataTime.find(" ");
68     std::string data = "";
69     std::string time = "";
70     if (position == dataTime.npos) {
71         data = dataTime;
72         if (data.find("-") == data.npos) {
73             data += "-01-01";
74         } else if (data.find_first_of("-") == data.find_last_of("-")) {
75             data += "-01";
76         }
77         time += " 00:00:00";
78     } else {
79         data = dataTime.substr(0, position);
80         time = dataTime.substr(position);
81         if (data.find("-") == data.npos) {
82             data += "-01-01";
83         } else if (data.find_first_of("-") == data.find_last_of("-")) {
84             data += "-01";
85         }
86         if (time.find(":") == data.npos) {
87             time += ":00:00";
88         } else if (time.find_first_of(":") == time.find_last_of(":")) {
89             time += ":00";
90         } else {
91             time = time.substr(0, time.find("."));
92         }
93     }
94     MEDIA_LOGD("AV_KEY_DATE_TIME_FORMAT is: %{public}s%{public}s", data.c_str(), time.c_str());
95     return data + time;
96 }
97 
PopulateMeta(Metadata & meta)98 void PopulateMeta(Metadata &meta)
99 {
100     for (const auto &item : AVMETA_KEY_TO_X_MAP) {
101         if (!meta.HasMeta(item.first)) {
102             if (item.first == AV_KEY_DATE_TIME_FORMAT && meta.HasMeta(AV_KEY_DATE_TIME)) {
103                 std::string dataTime = meta.GetMeta(AV_KEY_DATE_TIME);
104                 meta.SetMeta(item.first, FormatDataTime(dataTime));
105             } else {
106                 meta.SetMeta(item.first, "");
107             }
108         }
109     }
110 }
111 
112 struct AVMetaElemMetaCollector::TrackInfo {
113     bool valid = true;
114     Metadata uploadMeta;
115     Format innerMeta;
116 };
117 
Create(AVMetaSourceType type,const MetaResCb & resCb)118 std::unique_ptr<AVMetaElemMetaCollector> AVMetaElemMetaCollector::Create(AVMetaSourceType type, const MetaResCb &resCb)
119 {
120     switch (type) {
121         case AVMetaSourceType::TYPEFIND:
122             return std::make_unique<TypeFindMetaCollector>(type, resCb);
123         case AVMetaSourceType::DEMUXER:
124             return std::make_unique<DemuxerMetaCollector>(type, resCb);
125         case AVMetaSourceType::PARSER:
126             return std::make_unique<ParserMetaCollector>(type, resCb);
127         default:
128             MEDIA_LOGE("unknown type: %{public}hhu", type);
129             break;
130     }
131 
132     return nullptr;
133 }
134 
AVMetaElemMetaCollector(AVMetaSourceType type,const MetaResCb & resCb)135 AVMetaElemMetaCollector::AVMetaElemMetaCollector(AVMetaSourceType type, const MetaResCb &resCb)
136     : type_(type), resCb_(resCb)
137 {
138     MEDIA_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR ", type: %{public}hhu", FAKE_POINTER(this), type_);
139 }
140 
~AVMetaElemMetaCollector()141 AVMetaElemMetaCollector::~AVMetaElemMetaCollector()
142 {
143     MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
144 }
145 
Stop()146 void AVMetaElemMetaCollector::Stop()
147 {
148     std::unique_lock<std::mutex> lock(mutex_);
149     stopCollecting_ = true;
150 
151     for (auto &[elem, signalId] : signalIds_) {
152         g_signal_handler_disconnect(elem, signalId);
153     }
154     signalIds_.clear();
155 
156     for (auto &[pad, probeId] : padProbes_) {
157         gst_pad_remove_probe(pad, probeId);
158     }
159     padProbes_.clear();
160 
161     lock.unlock();
162     lock.lock();
163 }
164 
IsMetaCollected()165 bool AVMetaElemMetaCollector::IsMetaCollected()
166 {
167     std::unique_lock<std::mutex> lock(mutex_);
168     for (auto &[dummy, trackInfo] : trackInfos_) {
169         if (!trackInfo.valid) {
170             continue;
171         }
172         if (trackInfo.innerMeta.GetFormatMap().empty()) {
173             return false;
174         }
175     }
176 
177     // at least the duration meta and track count or container mime.
178     if (fileUploadMeta_.tbl_.empty()) {
179         return false;
180     }
181 
182     return true;
183 }
184 
FetchArtPicture()185 std::shared_ptr<AVSharedMemory> AVMetaElemMetaCollector::FetchArtPicture()
186 {
187     std::unique_lock<std::mutex> lock(mutex_);
188 
189     auto artPicMem = DoFetchArtPicture(fileInnerMeta_);
190     if (artPicMem != nullptr) {
191         return artPicMem;
192     }
193 
194     for (auto &[dummy, trackInnerMeta] : trackInfos_) {
195         artPicMem = DoFetchArtPicture(trackInnerMeta.innerMeta);
196         if (artPicMem != nullptr) {
197             return artPicMem;
198         }
199     }
200 
201     return artPicMem;
202 }
203 
DoFetchArtPicture(const Format & innerMeta)204 std::shared_ptr<AVSharedMemory> AVMetaElemMetaCollector::DoFetchArtPicture(const Format &innerMeta)
205 {
206     if (!innerMeta.ContainKey(INNER_META_KEY_IMAGE)) {
207         return nullptr;
208     }
209 
210     MEDIA_LOGD("has art picture");
211 
212     uint8_t *addr = nullptr;
213     size_t size = 0;
214     (void)innerMeta.GetBuffer(INNER_META_KEY_IMAGE, &addr, size);
215 
216     static constexpr size_t maxImageSize = 1 * 1024 * 1024;
217     if (addr == nullptr || size == 0 || size > maxImageSize) {
218         MEDIA_LOGW("invalid param, size = %{public}zu", size);
219         return nullptr;
220     }
221 
222     auto artPicMem = AVSharedMemoryBase::CreateFromLocal(
223         static_cast<int32_t>(size), AVSharedMemory::FLAGS_READ_ONLY, "artpic");
224     CHECK_AND_RETURN_RET_LOG(artPicMem != nullptr, nullptr, "create art pic failed");
225 
226     errno_t rc = memcpy_s(artPicMem->GetBase(), static_cast<size_t>(artPicMem->GetSize()), addr, size);
227     CHECK_AND_RETURN_RET_LOG(rc == EOK, nullptr, "memcpy_s failed");
228 
229     return artPicMem;
230 }
231 
AddProbeToPadList(GList & list)232 bool AVMetaElemMetaCollector::AddProbeToPadList(GList &list)
233 {
234     for (GList *padNode = g_list_first(&list); padNode != nullptr; padNode = padNode->next) {
235         if (padNode->data == nullptr) {
236             continue;
237         }
238 
239         GstPad *pad = reinterpret_cast<GstPad *>(padNode->data);
240         if (!AddProbeToPad(*pad)) {
241             return false;
242         }
243     }
244 
245     return true;
246 }
247 
AddProbeToPad(GstPad & pad)248 bool AVMetaElemMetaCollector::AddProbeToPad(GstPad &pad)
249 {
250     std::unique_lock<std::mutex> lock(mutex_);
251     if (stopCollecting_) {
252         MEDIA_LOGI("stop collecting...");
253         return false;
254     }
255 
256     gulong probeId = gst_pad_add_probe(&pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, ProbeCallback, this, nullptr);
257     if (probeId == 0) {
258         MEDIA_LOGE("add probe for %{public}s's pad %{public}s failed", PAD_PARENT_NAME(&pad), PAD_NAME(&pad));
259         return false;
260     }
261 
262     (void)padProbes_.emplace(&pad, probeId);
263     (void)trackInfos_.emplace(&pad, TrackInfo {});
264 
265     // report the track count change when caps arrived.
266     trackcount_ += 1;
267     MEDIA_LOGD("add probe to pad %{public}s of %{public}s", PAD_NAME(&pad), PAD_PARENT_NAME(&pad));
268     return true;
269 }
270 
ConnectSignal(GstElement & elem,std::string_view signal,GCallback callback)271 bool AVMetaElemMetaCollector::ConnectSignal(GstElement &elem, std::string_view signal, GCallback callback)
272 {
273     std::unique_lock<std::mutex> lock(mutex_);
274     if (stopCollecting_) {
275         MEDIA_LOGI("stop collecting...");
276         return false;
277     }
278 
279     gulong signalId = g_signal_connect(&elem, signal.data(), callback, this);
280     if (signalId == 0) {
281         MEDIA_LOGE("connect signal '%{public}s' to %{public}s failed", signal.data(), ELEM_NAME(&elem));
282         return false;
283     }
284 
285     (void)signalIds_.emplace(&elem, signalId);
286     return true;
287 }
288 
ProbeCallback(GstPad * pad,GstPadProbeInfo * info,gpointer usrdata)289 GstPadProbeReturn AVMetaElemMetaCollector::ProbeCallback(GstPad *pad, GstPadProbeInfo *info, gpointer usrdata)
290 {
291     if (pad == nullptr || info ==  nullptr || usrdata == nullptr) {
292         MEDIA_LOGE("param is invalid");
293         return GST_PAD_PROBE_OK;
294     }
295 
296     auto collector = reinterpret_cast<AVMetaElemMetaCollector *>(usrdata);
297     if (static_cast<unsigned int>(info->type) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
298         GstEvent *event = gst_pad_probe_info_get_event(info);
299         CHECK_AND_RETURN_RET_LOG(event != nullptr, GST_PAD_PROBE_OK, "event is null");
300         collector->OnEventProbe(*pad, *event);
301     }
302 
303     return GST_PAD_PROBE_OK;
304 }
305 
ParseTagList(const GstTagList & tagList,TrackInfo & trackInfo)306 void AVMetaElemMetaCollector::ParseTagList(const GstTagList &tagList, TrackInfo &trackInfo)
307 {
308     if (!trackInfo.valid) {
309         return;
310     }
311 
312     GstTagScope scope = gst_tag_list_get_scope(&tagList);
313     MEDIA_LOGI("catch tag %{public}s event", scope == GST_TAG_SCOPE_GLOBAL ? "global" : "stream");
314 
315     if (scope == GST_TAG_SCOPE_GLOBAL) {
316         if (globalTagCatched_) {
317             return;
318         }
319         globalTagCatched_ = true;
320         GstMetaParser::ParseTagList(tagList, fileInnerMeta_);
321         ConvertToAVMeta(fileInnerMeta_, fileUploadMeta_);
322         ReportMeta(fileUploadMeta_);
323     } else {
324         GstMetaParser::ParseTagList(tagList, trackInfo.innerMeta);
325         ConvertToAVMeta(trackInfo.innerMeta, trackInfo.uploadMeta);
326         ReportMeta(trackInfo.uploadMeta);
327     }
328 }
329 
ParseCaps(const GstCaps & caps,TrackInfo & trackInfo)330 void AVMetaElemMetaCollector::ParseCaps(const GstCaps &caps, TrackInfo &trackInfo)
331 {
332     GstMetaParser::ParseStreamCaps(caps, trackInfo.innerMeta);
333 
334     if (!EnsureTrackValid(trackInfo)) {
335         return;
336     }
337 
338     fileUploadMeta_.SetMeta(AV_KEY_NUM_TRACKS, std::to_string(trackcount_));
339     ReportMeta(fileUploadMeta_);
340 
341     ConvertToAVMeta(trackInfo.innerMeta, trackInfo.uploadMeta);
342     ReportMeta(trackInfo.uploadMeta);
343 }
344 
EnsureTrackValid(TrackInfo & trackInfo)345 bool AVMetaElemMetaCollector::EnsureTrackValid(TrackInfo &trackInfo)
346 {
347     /**
348      * If the track can not supported, it would not be taken account into the
349      * total track counts. The ffmpeg will generate one track for one image of
350      * the metadata, the track's caps is image/png or image/jpeg, etc. For such
351      * tracks, them should be considered as invalid tracks.
352      */
353     int32_t trackType;
354     std::string mimeType;
355     if (!trackInfo.innerMeta.GetIntValue(INNER_META_KEY_TRACK_TYPE, trackType) ||
356         !trackInfo.innerMeta.GetStringValue(INNER_META_KEY_MIME_TYPE, mimeType)) {
357         trackInfo.valid = false;
358         trackcount_ -= 1;
359         fileUploadMeta_.SetMeta(AV_KEY_NUM_TRACKS, std::to_string(trackcount_));
360         ReportMeta(fileUploadMeta_);
361         return false;
362     }
363 
364     if (trackType == MediaType::MEDIA_TYPE_VID) {
365         trackInfo.uploadMeta.SetMeta(AV_KEY_HAS_VIDEO, "yes");
366     } else if (trackType == MediaType::MEDIA_TYPE_AUD) {
367         trackInfo.uploadMeta.SetMeta(AV_KEY_HAS_AUDIO, "yes");
368     }
369 
370     return true;
371 }
372 
OnEventProbe(GstPad & pad,GstEvent & event)373 void AVMetaElemMetaCollector::OnEventProbe(GstPad &pad, GstEvent &event)
374 {
375     std::unique_lock<std::mutex> lock(mutex_);
376     if (stopCollecting_) {
377         MEDIA_LOGI("stop collecting...");
378         return;
379     }
380 
381     auto it = trackInfos_.find(&pad);
382     CHECK_AND_RETURN_LOG(it != trackInfos_.end(), "unrecognized pad %{public}s", PAD_NAME(&pad));
383 
384     if (GST_EVENT_TYPE(&event) == GST_EVENT_TAG) {
385         QueryDuration(pad);
386 
387         GstTagList *tagList = nullptr;
388         gst_event_parse_tag(&event, &tagList);
389         CHECK_AND_RETURN_LOG(tagList != nullptr, "taglist is nullptr");
390         MEDIA_LOGI("catch tags at pad %{public}s", PAD_NAME(&pad));
391         ParseTagList(*tagList, it->second);
392     }
393 
394     if (GST_EVENT_TYPE(&event) == GST_EVENT_CAPS) {
395         GstCaps *caps = nullptr;
396         gst_event_parse_caps(&event, &caps);
397         CHECK_AND_RETURN_LOG(caps != nullptr, "caps is nullptr");
398         MEDIA_LOGI("catch caps at pad %{public}s", PAD_NAME(&pad));
399         ParseCaps(*caps, it->second);
400     }
401 }
402 
QueryDuration(GstPad & pad)403 void AVMetaElemMetaCollector::QueryDuration(GstPad &pad)
404 {
405     GstQuery *query = gst_query_new_duration(GST_FORMAT_TIME);
406     CHECK_AND_RETURN_LOG(query != nullptr, "query is failed");
407 
408     gint64 streamDuration = 0;
409     if (gst_pad_query(&pad, query)) {
410         GstFormat format = GST_FORMAT_TIME;
411         gst_query_parse_duration(query, &format, &streamDuration);
412         if (!GST_CLOCK_TIME_IS_VALID(streamDuration)) {
413             streamDuration = 0;
414         }
415     }
416     gst_query_unref(query);
417 
418     if (duration_ < streamDuration) {
419         duration_ = streamDuration;
420         MEDIA_LOGI("update duration to %{public}" PRIi64 "", duration_);
421 
422         static constexpr int32_t NASEC_PER_MILLISEC = 1000000;
423         int64_t milliSecond = duration_ / NASEC_PER_MILLISEC; // ns -> ms
424         fileUploadMeta_.SetMeta(AV_KEY_DURATION, std::to_string(milliSecond));
425         ReportMeta(fileUploadMeta_);
426     }
427 }
428 
ReportMeta(const Metadata & uploadMeta)429 void AVMetaElemMetaCollector::ReportMeta(const Metadata &uploadMeta)
430 {
431     if (resCb_ == nullptr) {
432         return;
433     }
434 
435     mutex_.unlock();
436     resCb_(uploadMeta);
437     mutex_.lock();
438 }
439 
ConvertToAVMeta(const Format & innerMeta,Metadata & avmeta) const440 void AVMetaElemMetaCollector::ConvertToAVMeta(const Format &innerMeta, Metadata &avmeta) const
441 {
442     for (const auto &[avKey, innerKey] : AVMETA_KEY_TO_X_MAP) {
443         if (innerKey.compare("") == 0) {
444             continue;
445         }
446 
447         if (innerKey.compare(INNER_META_KEY_MIME_TYPE) == 0) { // only need the file mime type
448             continue;
449         }
450 
451         if (!innerMeta.ContainKey(innerKey)) {
452             continue;
453         }
454 
455         std::string strVal;
456         int32_t intVal;
457         FormatDataType type = innerMeta.GetValueType(innerKey);
458         switch (type) {
459             case FORMAT_TYPE_STRING:
460                 innerMeta.GetStringValue(innerKey, strVal);
461                 avmeta.SetMeta(avKey, strVal);
462                 break;
463             case FORMAT_TYPE_INT32:
464                 innerMeta.GetIntValue(innerKey, intVal);
465                 avmeta.SetMeta(avKey, std::to_string(intVal));
466                 break;
467             default:
468                 break;
469         }
470     }
471 }
472 
473 /**
474  * Detail Element Meta Collector Implementation Begin.
475  */
476 
HaveTypeCallback(GstElement * elem,guint probability,GstCaps * caps,gpointer userData)477 void TypeFindMetaCollector::HaveTypeCallback(GstElement *elem, guint probability, GstCaps *caps, gpointer userData)
478 {
479     if (elem == nullptr || caps == nullptr || userData == nullptr) {
480         return;
481     }
482 
483     MEDIA_LOGD("typefind %{public}s have type, probalibity = %{public}u", ELEM_NAME(elem), probability);
484 
485     TypeFindMetaCollector *collector = reinterpret_cast<TypeFindMetaCollector *>(userData);
486     collector->OnHaveType(*elem, *caps);
487 }
488 
OnHaveType(const GstElement & elem,const GstCaps & caps)489 void TypeFindMetaCollector::OnHaveType(const GstElement &elem, const GstCaps &caps)
490 {
491     (void)elem;
492     std::unique_lock<std::mutex> lock(mutex_);
493     if (stopCollecting_) {
494         MEDIA_LOGI("stop collecting...");
495         return;
496     }
497 
498     GstMetaParser::ParseFileMimeType(caps, fileInnerMeta_);
499 
500     std::string mimeType;
501     (void)fileInnerMeta_.GetStringValue(INNER_META_KEY_MIME_TYPE, mimeType);
502     fileUploadMeta_.SetMeta(AV_KEY_MIME_TYPE, mimeType);
503 
504     ReportMeta(fileUploadMeta_);
505 }
506 
AddMetaSource(GstElement & elem)507 void TypeFindMetaCollector::AddMetaSource(GstElement &elem)
508 {
509     (void)ConnectSignal(elem, "have-type", G_CALLBACK(&TypeFindMetaCollector::HaveTypeCallback));
510 }
511 
PadAddedCallback(GstElement * elem,GstPad * pad,gpointer userData)512 void DemuxerMetaCollector::PadAddedCallback(GstElement *elem, GstPad *pad, gpointer userData)
513 {
514     if (elem == nullptr || pad == nullptr || userData == nullptr) {
515         return;
516     }
517 
518     auto collector = reinterpret_cast<DemuxerMetaCollector *>(userData);
519     collector->OnPadAdded(*elem, *pad);
520 }
521 
OnPadAdded(GstElement & src,GstPad & pad)522 void DemuxerMetaCollector::OnPadAdded(GstElement &src, GstPad &pad)
523 {
524     MEDIA_LOGD("demuxer %{public}s sinkpad %{public}s added", ELEM_NAME(&src), PAD_NAME(&pad));
525     (void)AddProbeToPad(pad);
526 }
527 
AddMetaSource(GstElement & elem)528 void DemuxerMetaCollector::AddMetaSource(GstElement &elem)
529 {
530     if (!AddProbeToPadList(*elem.srcpads)) {
531         return;
532     }
533 
534     (void)ConnectSignal(elem, "pad-added", G_CALLBACK(&DemuxerMetaCollector::PadAddedCallback));
535 }
536 
AddMetaSource(GstElement & elem)537 void ParserMetaCollector::AddMetaSource(GstElement &elem)
538 {
539     (void)AddProbeToPadList(*elem.srcpads);
540 }
541 } // namespace Media
542 } // namespace OHOS