Skip to content

Commit dc705bc

Browse files
vivienne-weocanha
authored andcommitted
[GStreamer] Set audio track ID to stream value in regular playback
https://bugs.webkit.org/show_bug.cgi?id=260520 Reviewed by Xabier Rodriguez-Calvar. This change only affects playbin2 implementations (regular playback), where tracks are based on pads instead of in streams. The proper track IDs are only actually available when the stream-start bus message is received. The track creation is delayed until that moment. At that point, all the audio and video pads handled by GStreamer are processed and the corresponding audio/video tracks are created. The proper track IDs are present at that moment. This means that the old audio/videoChanged callbacks aren't needed anymore. After that, we listen to changes in caps and tags in the pad and trigger the needed updates, which will complete the information available for the corresponding track. Some approaches that were tried and resulted to be unsuccessful: Trying to create the track the first time (on video-changed or audio-changed), already with the definitive id isn't a valid approach, since the sticky stream-start event isn't available at that moment. Creating the track with a synthesized id and then updating it when the stream-start event is available isn't a good idea, because the only way to update the track is by removing it from audio/videoTracks and readding it, and that triggers spureous events visible from JavaScript. Therefore, the proper way was to delay track creation until stream-start comes. Trying to install a probe on the audio/video pads and detecting the stream-start event from there (instead of relying on the bus message), but calling the track manipulation code from a non-main thread would be unsafe and would require deferring the manipulation to the main thread. Even in that case, there's no guarantee for the stream-start sticky event to be available when the manipulation code runs in the main thread, because that sticky event is stored after probe processing and there's a race. Some layout tests had to be changed to refer to the tracks by index instead of by track id. The GStreamer based ports now return the native id embedded in the stream container, while Apple ports still use synthesized ids (A1, A2, V1...). That was the best way to deal with the differences without duplicating the tests for different platforms. Co-authored by Enrique Ocaña González <eocanha@igalia.com> * LayoutTests/media/track/audio/audio-track-mkv-vorbis-language-expected.txt: Changed expected output. * LayoutTests/media/track/audio/audio-track-mkv-vorbis-language.html: Refer to the tracks by index instead of by id. * LayoutTests/media/track/video/video-track-mkv-theora-language-expected.txt: Changed expected output. * LayoutTests/media/track/video/video-track-mkv-theora-language.html: Refer to the tracks by index instead of by id. * Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp: (WebCore::AudioTrackPrivateGStreamer::AudioTrackPrivateGStreamer): Install configuration change handlers. Use move semantics. (WebCore::AudioTrackPrivateGStreamer::capsChanged): Updated signature, use move semantics. (WebCore::AudioTrackPrivateGStreamer::updateConfigurationFromTags): Updated signature. (WebCore::AudioTrackPrivateGStreamer::updateConfigurationFromCaps): Ditto. * Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.h: Declare configuration change handlers as overridding the base implementation. Updated some signatures to use r-value references. * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp: (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfTrack): Set track IDs (now always valid and final at this point, unlike before) and only notify the media engine if actual changes have been made. This is because this method can now be called even if no tracks of the given type have appeared. (WebCore::MediaPlayerPrivateGStreamer::handleMessage): Listen to stream-start bus message and unconditionally notify for audio/video track creation. notifyPlayerOfTrack() will know if tracks of each type have been created or not. (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin): Don't listen audio/video/text-changed anymore. We now have everything we need when stream-start comes. (WebCore::MediaPlayerPrivateGStreamer::audioChangedCallback): Deleted. (WebCore::MediaPlayerPrivateGStreamer::textChangedCallback): Deleted. (WebCore::MediaPlayerPrivateGStreamer::videoChangedCallback): Deleted. * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h: Deleted audio/video/textChangedCallback(). * Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp: (WebCore::findBestUpstreamPad): Added protection against null pad. (WebCore::TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer): Generate ID from pad stream-start or synthesize one. This factors in common code and avoids repetition. (WebCore::TrackPrivateBaseGStreamer::setPad): Protect against null m_bestUpstreamPad and reuse preexistent streamId from track. (WebCore::TrackPrivateBaseGStreamer::tagsChanged): Initialize tags list to avoid uninitialized pointer in case parsing fails. Use move semantics. (WebCore::TrackPrivateBaseGStreamer::capsChanged): Use move semantics. (WebCore::TrackPrivateBaseGStreamer::notifyTrackOfTagsChanged): Avoid leak. Use move semantics. (WebCore::TrackPrivateBaseGStreamer::notifyTrackOfStreamChanged): Protect against null pad. (WebCore::TrackPrivateBaseGStreamer::installUpdateConfigurationHandlers): Listen to caps and tags changes and update configuration accordingly by calling the abstract handlers (to be implemented by subclasses as needed, empty by default). This installation works for pad-based (playbin2) as well as stream-based (playbin3) variants. (WebCore::TrackPrivateBaseGStreamer::updateConfigurationFromCaps): Use r-value references. (WebCore::TrackPrivateBaseGStreamer::updateConfigurationFromTags): Ditto. (WebCore::TrackPrivateBaseGStreamer::trackIdFromPadStreamStartOrUniqueID): Extract the track ID name from the pad, or synthesize an ID if it can't be extracted. (WebCore::TrackPrivateBaseGStreamer::getAllTags): Utility function to merge multiple tags stored in a pad as a sticky tags event. * Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.h: Factored in common code into trackIdFromPadStreamStartOrUniqueID(). Added default empty abstract implementations of configuration change handlers and common method to install them, for those subclasses that chose to do so. Use r-value references in some signatures. * Source/WebCore/platform/graphics/gstreamer/VideoTrackPrivateGStreamer.h: Declare configuration change handlers as overridding the base implementation. * Source/WebCore/platform/graphics/gstreamer/VideoTrackPrivateGStreamer.cpp: (WebCore::VideoTrackPrivateGStreamer::VideoTrackPrivateGStreamer): Install configuration change handlers. (WebCore::VideoTrackPrivateGStreamer::capsChanged): Use move semantics. (WebCore::VideoTrackPrivateGStreamer::updateConfigurationFromTags): Ditto. (WebCore::VideoTrackPrivateGStreamer::updateConfigurationFromCaps): Ditto. Canonical link: https://commits.webkit.org/268194@main
1 parent fce8e2e commit dc705bc

8 files changed

Lines changed: 163 additions & 86 deletions

Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ AudioTrackPrivateGStreamer::AudioTrackPrivateGStreamer(WeakPtr<MediaPlayerPrivat
4040
: TrackPrivateBaseGStreamer(TrackPrivateBaseGStreamer::TrackType::Audio, this, index, WTFMove(pad), shouldHandleStreamStartEvent)
4141
, m_player(player)
4242
{
43+
installUpdateConfigurationHandlers();
4344
}
4445

4546
AudioTrackPrivateGStreamer::AudioTrackPrivateGStreamer(WeakPtr<MediaPlayerPrivateGStreamer> player, unsigned index, GstStream* stream)
@@ -54,16 +55,7 @@ AudioTrackPrivateGStreamer::AudioTrackPrivateGStreamer(WeakPtr<MediaPlayerPrivat
5455
gst_stream_set_stream_flags(m_stream.get(), static_cast<GstStreamFlags>(streamFlags | GST_STREAM_FLAG_SELECT));
5556
}
5657

57-
g_signal_connect_swapped(m_stream.get(), "notify::caps", G_CALLBACK(+[](AudioTrackPrivateGStreamer* track) {
58-
track->m_taskQueue.enqueueTask([track]() {
59-
track->updateConfigurationFromCaps();
60-
});
61-
}), this);
62-
g_signal_connect_swapped(m_stream.get(), "notify::tags", G_CALLBACK(+[](AudioTrackPrivateGStreamer* track) {
63-
track->m_taskQueue.enqueueTask([track]() {
64-
track->updateConfigurationFromTags();
65-
});
66-
}), this);
58+
installUpdateConfigurationHandlers();
6759

6860
updateConfigurationFromCaps();
6961
updateConfigurationFromTags();
@@ -72,14 +64,22 @@ AudioTrackPrivateGStreamer::AudioTrackPrivateGStreamer(WeakPtr<MediaPlayerPrivat
7264
void AudioTrackPrivateGStreamer::updateConfigurationFromTags()
7365
{
7466
ASSERT(isMainThread());
75-
if (!m_stream)
76-
return;
67+
GRefPtr<GstTagList> tags;
68+
69+
if (m_stream)
70+
tags = adoptGRef(gst_stream_get_tags(m_stream.get()));
71+
else if (m_pad)
72+
tags = getAllTags(m_pad.get());
7773

78-
auto tags = adoptGRef(gst_stream_get_tags(m_stream.get()));
7974
unsigned bitrate;
8075
if (!tags || !gst_tag_list_get_uint(tags.get(), GST_TAG_BITRATE, &bitrate))
8176
return;
8277

78+
if (m_stream)
79+
GST_DEBUG_OBJECT(m_stream.get(), "Setting bitrate to %u", bitrate);
80+
else if (m_pad)
81+
GST_DEBUG_OBJECT(m_pad.get(), "Setting bitrate to %u", bitrate);
82+
8383
auto configuration = this->configuration();
8484
configuration.bitrate = bitrate;
8585
setConfiguration(WTFMove(configuration));
@@ -88,10 +88,13 @@ void AudioTrackPrivateGStreamer::updateConfigurationFromTags()
8888
void AudioTrackPrivateGStreamer::updateConfigurationFromCaps()
8989
{
9090
ASSERT(isMainThread());
91-
if (!m_stream)
92-
return;
91+
GRefPtr<GstCaps> caps;
92+
93+
if (m_stream)
94+
caps = adoptGRef(gst_stream_get_caps(m_stream.get()));
95+
else if (m_pad)
96+
caps = adoptGRef(gst_pad_get_current_caps(m_pad.get()));
9397

94-
auto caps = adoptGRef(gst_stream_get_caps(m_stream.get()));
9598
if (!caps || !gst_caps_is_fixed(caps.get()))
9699
return;
97100

Source/WebCore/platform/graphics/gstreamer/AudioTrackPrivateGStreamer.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
#if ENABLE(VIDEO) && USE(GSTREAMER)
2929

30-
#include "AbortableTaskQueue.h"
3130
#include "AudioTrackPrivate.h"
3231
#include "TrackPrivateBaseGStreamer.h"
3332

@@ -60,11 +59,10 @@ class AudioTrackPrivateGStreamer final : public AudioTrackPrivate, public TrackP
6059
AtomString id() const final { return m_id; }
6160
AtomString label() const final { return m_label; }
6261
AtomString language() const final { return m_language; }
63-
AbortableTaskQueue m_taskQueue;
6462

6563
protected:
66-
void updateConfigurationFromCaps();
67-
void updateConfigurationFromTags();
64+
void updateConfigurationFromCaps() override;
65+
void updateConfigurationFromTags() override;
6866

6967
private:
7068
AudioTrackPrivateGStreamer(WeakPtr<MediaPlayerPrivateGStreamer>, unsigned index, GRefPtr<GstPad>&&, bool shouldHandleStreamStartEvent);

Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,15 +1049,15 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfTrack()
10491049
StringPrintStream getPadProperty;
10501050
getPadProperty.printf("get-%s-pad", typeName);
10511051

1052+
bool changed = false;
10521053
for (unsigned i = 0; i < numberOfTracks; ++i) {
10531054
GRefPtr<GstPad> pad;
10541055
g_signal_emit_by_name(m_pipeline.get(), getPadProperty.toCString().data(), i, &pad.outPtr(), nullptr);
10551056
ASSERT(pad);
1057+
if (!pad)
1058+
continue;
10561059

1057-
// The pad might not have a sticky stream-start event yet, so we can't use
1058-
// gst_pad_get_stream_id() here.
1059-
auto streamId = TrackPrivateBaseGStreamer::generateUniquePlaybin2StreamID(type, i);
1060-
validStreams.append(streamId);
1060+
AtomString streamId(TrackPrivateBaseGStreamer::trackIdFromPadStreamStartOrUniqueID(type, i, pad));
10611061

10621062
if (i < tracks.size()) {
10631063
RefPtr<TrackPrivateType> existingTrack = tracks.get(streamId);
@@ -1071,7 +1071,9 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfTrack()
10711071
}
10721072
}
10731073

1074-
auto track = TrackPrivateType::create(*this, i, WTFMove(pad));
1074+
auto track = TrackPrivateType::create(*this, i, GRefPtr(pad));
1075+
ASSERT(track->id() == streamId);
1076+
validStreams.append(track->id());
10751077
if (!track->trackIndex() && (type == TrackType::Audio || type == TrackType::Video))
10761078
track->setActive(true);
10771079
ASSERT(streamId == track->id());
@@ -1088,15 +1090,17 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfTrack()
10881090
m_player->addTextTrack(*std::get<InbandTextTrackPrivate*>(variantTrack));
10891091
break;
10901092
}
1091-
tracks.add(streamId, WTFMove(track));
1093+
tracks.add(track->id(), WTFMove(track));
1094+
changed = true;
10921095
}
10931096

10941097
// Purge invalid tracks
1095-
tracks.removeIf([validStreams](auto& keyAndValue) {
1098+
changed = changed || tracks.removeIf([validStreams](auto& keyAndValue) {
10961099
return !validStreams.contains(keyAndValue.key);
10971100
});
10981101

1099-
m_player->mediaEngineUpdated();
1102+
if (changed)
1103+
m_player->mediaEngineUpdated();
11001104
}
11011105

11021106
bool MediaPlayerPrivateGStreamer::hasFirstVideoSampleReachedSink() const
@@ -1130,20 +1134,6 @@ void MediaPlayerPrivateGStreamer::videoSinkCapsChanged(GstPad* videoSinkPad)
11301134
});
11311135
}
11321136

1133-
void MediaPlayerPrivateGStreamer::audioChangedCallback(MediaPlayerPrivateGStreamer* player)
1134-
{
1135-
player->m_notifier->notify(MainThreadNotification::AudioChanged, [player] {
1136-
player->notifyPlayerOfTrack<AudioTrackPrivateGStreamer>();
1137-
});
1138-
}
1139-
1140-
void MediaPlayerPrivateGStreamer::textChangedCallback(MediaPlayerPrivateGStreamer* player)
1141-
{
1142-
player->m_notifier->notify(MainThreadNotification::TextChanged, [player] {
1143-
player->notifyPlayerOfTrack<InbandTextTrackPrivateGStreamer>();
1144-
});
1145-
}
1146-
11471137
void MediaPlayerPrivateGStreamer::handleTextSample(GstSample* sample, const char* streamId)
11481138
{
11491139
for (auto& track : m_textTracks.values()) {
@@ -1539,13 +1529,6 @@ void MediaPlayerPrivateGStreamer::updateTracks(const GRefPtr<GstObject>& collect
15391529
#undef CREATE_OR_SELECT_TRACK
15401530
}
15411531

1542-
void MediaPlayerPrivateGStreamer::videoChangedCallback(MediaPlayerPrivateGStreamer* player)
1543-
{
1544-
player->m_notifier->notify(MainThreadNotification::VideoChanged, [player] {
1545-
player->notifyPlayerOfTrack<VideoTrackPrivateGStreamer>();
1546-
});
1547-
}
1548-
15491532
void MediaPlayerPrivateGStreamer::handleStreamCollectionMessage(GstMessage* message)
15501533
{
15511534
if (m_isLegacyPlaybin)
@@ -2064,6 +2047,16 @@ void MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
20642047
playbin3SendSelectStreamsIfAppropriate();
20652048
break;
20662049
}
2050+
case GST_MESSAGE_STREAM_START: {
2051+
// Real track id configuration in MSE is managed by AppendPipeline. In MediaStream we don't support native stream ids.
2052+
if (!m_isLegacyPlaybin)
2053+
break;
2054+
2055+
notifyPlayerOfTrack<VideoTrackPrivateGStreamer>();
2056+
notifyPlayerOfTrack<AudioTrackPrivateGStreamer>();
2057+
notifyPlayerOfTrack<InbandTextTrackPrivateGStreamer>();
2058+
break;
2059+
}
20672060
default:
20682061
GST_DEBUG_OBJECT(pipeline(), "Unhandled GStreamer message type: %s", GST_MESSAGE_TYPE_NAME(message));
20692062
break;
@@ -2956,13 +2949,6 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin(const URL& url)
29562949
}), this);
29572950

29582951
g_signal_connect_swapped(m_pipeline.get(), "source-setup", G_CALLBACK(sourceSetupCallback), this);
2959-
if (m_isLegacyPlaybin) {
2960-
g_signal_connect_swapped(m_pipeline.get(), "video-changed", G_CALLBACK(videoChangedCallback), this);
2961-
g_signal_connect_swapped(m_pipeline.get(), "audio-changed", G_CALLBACK(audioChangedCallback), this);
2962-
}
2963-
2964-
if (m_isLegacyPlaybin)
2965-
g_signal_connect_swapped(m_pipeline.get(), "text-changed", G_CALLBACK(textChangedCallback), this);
29662952

29672953
if (auto* textCombiner = webkitTextCombinerNew())
29682954
g_object_set(m_pipeline.get(), "text-stream-combiner", textCombiner, nullptr);

Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface
352352
void invalidateCachedPosition() const;
353353

354354
static void sourceSetupCallback(MediaPlayerPrivateGStreamer*, GstElement*);
355-
static void videoChangedCallback(MediaPlayerPrivateGStreamer*);
356-
static void audioChangedCallback(MediaPlayerPrivateGStreamer*);
357-
static void textChangedCallback(MediaPlayerPrivateGStreamer*);
358355

359356
void timeChanged();
360357
void loadingFailed(MediaPlayer::NetworkState, MediaPlayer::ReadyState = MediaPlayer::ReadyState::HaveNothing, bool forceNotifications = false);

Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer(TrackType type, TrackPrivat
8181
setPad(WTFMove(pad));
8282
ASSERT(m_pad);
8383

84+
m_id = AtomString(trackIdFromPadStreamStartOrUniqueID(type, index, m_pad));
85+
8486
// We can't call notifyTrackOfTagsChanged() directly, because we need tagsChanged() to setup m_tags.
8587
tagsChanged();
8688
}
@@ -110,7 +112,10 @@ void TrackPrivateBaseGStreamer::setPad(GRefPtr<GstPad>&& pad)
110112

111113
m_pad = WTFMove(pad);
112114
m_bestUpstreamPad = findBestUpstreamPad(m_pad);
113-
m_id = generateUniquePlaybin2StreamID(m_type, m_index);
115+
m_id = AtomString(trackIdFromPadStreamStartOrUniqueID(m_type, m_index, m_pad));
116+
117+
if (!m_bestUpstreamPad)
118+
return;
114119

115120
m_eventProbe = gst_pad_add_probe(m_bestUpstreamPad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, [] (GstPad*, GstPadProbeInfo* info, gpointer userData) -> GstPadProbeReturn {
116121
auto* track = static_cast<TrackPrivateBaseGStreamer*>(userData);
@@ -164,7 +169,7 @@ void TrackPrivateBaseGStreamer::tagsChanged()
164169
do {
165170
tagEvent = adoptGRef(gst_pad_get_sticky_event(m_bestUpstreamPad.get(), GST_EVENT_TAG, i));
166171
if (tagEvent) {
167-
GstTagList* tagsFromEvent;
172+
GstTagList* tagsFromEvent = nullptr;
168173
gst_event_parse_tag(tagEvent.get(), &tagsFromEvent);
169174
tags = adoptGRef(gst_tag_list_copy(tagsFromEvent));
170175
String language;
@@ -246,6 +251,9 @@ void TrackPrivateBaseGStreamer::notifyTrackOfTagsChanged()
246251

247252
void TrackPrivateBaseGStreamer::notifyTrackOfStreamChanged()
248253
{
254+
if (!m_pad)
255+
return;
256+
249257
GUniquePtr<char> streamId(gst_pad_get_stream_id(m_pad.get()));
250258
if (!streamId)
251259
return;
@@ -261,6 +269,81 @@ void TrackPrivateBaseGStreamer::streamChanged()
261269
});
262270
}
263271

272+
void TrackPrivateBaseGStreamer::installUpdateConfigurationHandlers()
273+
{
274+
if (m_pad) {
275+
g_signal_connect_swapped(m_pad.get(), "notify::caps", G_CALLBACK(+[](TrackPrivateBaseGStreamer* track) {
276+
track->m_taskQueue.enqueueTask([track]() {
277+
if (!track->m_pad)
278+
return;
279+
auto caps = adoptGRef(gst_pad_get_current_caps(track->m_pad.get()));
280+
if (!caps)
281+
return;
282+
track->updateConfigurationFromCaps();
283+
});
284+
}), this);
285+
g_signal_connect_swapped(m_pad.get(), "notify::tags", G_CALLBACK(+[](TrackPrivateBaseGStreamer* track) {
286+
track->m_taskQueue.enqueueTask([track]() {
287+
if (!track->m_pad)
288+
return;
289+
track->updateConfigurationFromTags();
290+
});
291+
}), this);
292+
} else if (m_stream) {
293+
g_signal_connect_swapped(m_stream.get(), "notify::caps", G_CALLBACK(+[](TrackPrivateBaseGStreamer* track) {
294+
track->m_taskQueue.enqueueTask([track]() {
295+
track->updateConfigurationFromCaps();
296+
});
297+
}), this);
298+
g_signal_connect_swapped(m_stream.get(), "notify::tags", G_CALLBACK(+[](TrackPrivateBaseGStreamer* track) {
299+
if (isMainThread())
300+
track->updateConfigurationFromTags();
301+
else
302+
track->m_taskQueue.enqueueTask([track]() {
303+
track->updateConfigurationFromTags();
304+
});
305+
}), this);
306+
}
307+
}
308+
309+
String TrackPrivateBaseGStreamer::trackIdFromPadStreamStartOrUniqueID(TrackType type, unsigned index, const GRefPtr<GstPad>& pad)
310+
{
311+
String streamId = nullString();
312+
if (!pad)
313+
return generateUniquePlaybin2StreamID(type, index);
314+
315+
auto streamStart = adoptGRef(gst_pad_get_sticky_event(pad.get(), GST_EVENT_STREAM_START, 0));
316+
if (!streamStart)
317+
return generateUniquePlaybin2StreamID(type, index);
318+
319+
const gchar* streamIdAsCharacters;
320+
gst_event_parse_stream_start(streamStart.get(), &streamIdAsCharacters);
321+
322+
if (!streamIdAsCharacters)
323+
return generateUniquePlaybin2StreamID(type, index);
324+
325+
StringView streamIdView = StringView::fromLatin1(streamIdAsCharacters);
326+
size_t position = streamIdView.find('/');
327+
if (position == notFound || position + 1 == streamIdView.length())
328+
return generateUniquePlaybin2StreamID(type, index);
329+
330+
return streamIdView.substring(position + 1).toString();
331+
}
332+
333+
GRefPtr<GstTagList> TrackPrivateBaseGStreamer::getAllTags(const GRefPtr<GstPad>& pad)
334+
{
335+
auto allTags = adoptGRef(gst_tag_list_new_empty());
336+
GstTagList* taglist = nullptr;
337+
for (guint i = 0;; i++) {
338+
GRefPtr<GstEvent> tagsEvent = adoptGRef(gst_pad_get_sticky_event(pad.get(), GST_EVENT_TAG, i));
339+
if (!tagsEvent)
340+
break;
341+
gst_event_parse_tag(tagsEvent.get(), &taglist);
342+
allTags = adoptGRef(gst_tag_list_merge(allTags.get(), taglist, GST_TAG_MERGE_APPEND));
343+
}
344+
return allTags;
345+
}
346+
264347
} // namespace WebCore
265348

266349
#endif // ENABLE(VIDEO) && USE(GSTREAMER)

Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#if ENABLE(VIDEO) && USE(GSTREAMER)
2929

30+
#include "AbortableTaskQueue.h"
3031
#include "GStreamerCommon.h"
3132
#include "MainThreadNotifier.h"
3233
#include <gst/gst.h>
@@ -66,12 +67,19 @@ class TrackPrivateBaseGStreamer {
6667
void setInitialCaps(GRefPtr<GstCaps>&& caps) { m_initialCaps = WTFMove(caps); }
6768
const GRefPtr<GstCaps>& initialCaps() { return m_initialCaps; }
6869

70+
static String trackIdFromPadStreamStartOrUniqueID(TrackType, unsigned index, const GRefPtr<GstPad>&);
71+
6972
protected:
7073
TrackPrivateBaseGStreamer(TrackType, TrackPrivateBase*, unsigned index, GRefPtr<GstPad>&&, bool shouldHandleStreamStartEvent);
7174
TrackPrivateBaseGStreamer(TrackType, TrackPrivateBase*, unsigned index, GstStream*);
7275

7376
void notifyTrackOfTagsChanged();
7477
void notifyTrackOfStreamChanged();
78+
void installUpdateConfigurationHandlers();
79+
virtual void updateConfigurationFromCaps() { }
80+
virtual void updateConfigurationFromTags() { }
81+
82+
static GRefPtr<GstTagList> getAllTags(const GRefPtr<GstPad>&);
7583

7684
enum MainThreadNotification {
7785
TagsChanged = 1 << 1,
@@ -89,6 +97,7 @@ class TrackPrivateBaseGStreamer {
8997
GRefPtr<GstStream> m_stream;
9098
unsigned long m_eventProbe { 0 };
9199
GRefPtr<GstCaps> m_initialCaps;
100+
AbortableTaskQueue m_taskQueue;
92101

93102
private:
94103
bool getLanguageCode(GstTagList* tags, AtomString& value);

0 commit comments

Comments
 (0)