Changeset 263836 in webkit
- Timestamp:
- Jul 2, 2020, 1:20:51 AM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
-
ChangeLog (modified) (1 diff)
-
platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (modified) (1 diff)
-
platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp (modified) (12 diffs)
-
platform/mediastream/gstreamer/GStreamerMediaStreamSource.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r263832 r263836 1 2020-07-02 Philippe Normand <pnormand@igalia.com> 2 3 [GStreamer] Rewrite mediastreamsrc element 4 https://bugs.webkit.org/show_bug.cgi?id=213777 5 6 Reviewed by Xabier Rodriguez-Calvar. 7 8 The underlying functionality remains the same, design-wise. This is mostly a refactoring 9 switching to smart pointers as much as possible and trying to comply with WebKit code style 10 guidelines. 11 12 The previous version of this element was leaking pad templates and sticky stream-start 13 events (in webkitMediaStreamSrcTrackEnded). 14 15 The LIBWEBRTC ifdef guards were removed as well, because there's no actual libwebrtc 16 dependency involved in this code. 17 18 No new tests, existing webrtc and fast/mediastream tests cover this patch. 19 20 * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp: 21 * platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp: 22 (mediaStreamTrackPrivateGetTags): 23 (webkitMediaStreamNew): 24 (WebKitMediaStreamTrackObserver::WebKitMediaStreamTrackObserver): 25 (WebKitMediaStreamObserver::WebKitMediaStreamObserver): 26 (InternalSource::InternalSource): 27 (InternalSource::~InternalSource): 28 (InternalSource::src const): 29 (InternalSource::pushSample): 30 (webkitMediaStreamSrcUriGetType): 31 (webkitMediaStreamSrcUriGetProtocols): 32 (webkitMediaStreamSrcUriGetUri): 33 (webkitMediaStreamSrcUriSetUri): 34 (webkitMediaStreamSrcUriHandlerInit): 35 (webkitMediaStreamSrcSetProperty): 36 (webkitMediaStreamSrcGetProperty): 37 (webkitMediaStreamSrcConstructed): 38 (stopObservingTracks): 39 (webkitMediaStreamSrcFinalize): 40 (webkitMediaStreamSrcChangeState): 41 (webkit_media_stream_src_class_init): 42 (webkitMediaStreamSrcChain): 43 (webkitMediaStreamSrcAddPad): 44 (ProbeData::ProbeData): 45 (webkitMediaStreamSrcPadProbeCb): 46 (webkitMediaStreamSrcSetupSrc): 47 (webkitMediaStreamSrcPostStreamCollection): 48 (webkitMediaStreamSrcAddTrack): 49 (webkitMediaStreamSrcRemoveTrackByType): 50 (webkitMediaStreamSrcSetStream): 51 (webkitMediaStreamSrcPushVideoSample): 52 (webkitMediaStreamSrcPushAudioSample): 53 (webkitMediaStreamSrcTrackEnded): 54 (webkitMediaStreamSrcNew): 55 * platform/mediastream/gstreamer/GStreamerMediaStreamSource.h: 56 1 57 2020-07-01 Said Abou-Hallawa <sabouhallawa@apple.com> 2 58 -
trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
r263658 r263836 54 54 #if ENABLE(MEDIA_STREAM) 55 55 #include "GStreamerMediaStreamSource.h" 56 #include "MediaStreamPrivate.h" 56 57 #endif 57 58 -
trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp
r263457 r263836 1 1 /* 2 2 * Copyright (C) 2018 Metrological Group B.V. 3 * Copyright (C) 2020 Igalia S.L. 3 4 * Author: Thibault Saunier <tsaunier@igalia.com> 4 5 * Author: Alejandro G. Castro <alex@igalia.com> 6 * Author: Philippe Normand <philn@igalia.com> 5 7 * 6 8 * This library is free software; you can redistribute it and/or … … 21 23 22 24 #include "config.h" 23 24 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)25 25 #include "GStreamerMediaStreamSource.h" 26 27 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER) 26 28 27 29 #include "AudioTrackPrivate.h" … … 30 32 #include "GStreamerVideoCaptureSource.h" 31 33 #include "MediaSampleGStreamer.h" 34 #include "MediaStreamPrivate.h" 35 #include "MediaStreamTrackPrivate.h" 32 36 #include "VideoTrackPrivate.h" 33 37 34 38 #include <gst/app/gstappsrc.h> 35 #include <gst/base/gstflowcombiner.h> 36 37 namespace WebCore { 38 39 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc* self, GstSample* gstsample); 40 static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc* self, GstSample* gstsample); 41 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate&); 42 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc* self, RealtimeMediaSource::Type trackType); 43 44 static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src", 45 GST_PAD_SRC, 46 GST_PAD_SOMETIMES, 39 #include <wtf/glib/WTFGType.h> 40 41 using namespace WebCore; 42 43 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc*, GstSample*); 44 static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc*, GstSample*); 45 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc*, MediaStreamTrackPrivate&); 46 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc*, RealtimeMediaSource::Type); 47 48 static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src", GST_PAD_SRC, GST_PAD_SOMETIMES, 47 49 GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8")); 48 50 49 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src", 50 GST_PAD_SRC, 51 GST_PAD_SOMETIMES, 51 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src", GST_PAD_SRC, GST_PAD_SOMETIMES, 52 52 GST_STATIC_CAPS("audio/x-raw(ANY);")); 53 53 54 static GstTagList* mediaStreamTrackPrivateGetTags(MediaStreamTrackPrivate* track) 55 { 56 auto taglist = gst_tag_list_new_empty(); 57 58 if (!track->label().isEmpty()) { 59 gst_tag_list_add(taglist, GST_TAG_MERGE_APPEND, 60 GST_TAG_TITLE, track->label().utf8().data(), nullptr); 61 } 62 63 if (track->type() == RealtimeMediaSource::Type::Audio) { 64 gst_tag_list_add(taglist, GST_TAG_MERGE_APPEND, WEBKIT_MEDIA_TRACK_TAG_KIND, 65 static_cast<int>(AudioTrackPrivate::Kind::Main), nullptr); 66 } else if (track->type() == RealtimeMediaSource::Type::Video) { 67 gst_tag_list_add(taglist, GST_TAG_MERGE_APPEND, WEBKIT_MEDIA_TRACK_TAG_KIND, 68 static_cast<int>(VideoTrackPrivate::Kind::Main), nullptr); 54 GRefPtr<GstTagList> mediaStreamTrackPrivateGetTags(MediaStreamTrackPrivate* track) 55 { 56 auto tagList = adoptGRef(gst_tag_list_new_empty()); 57 58 if (!track->label().isEmpty()) 59 gst_tag_list_add(tagList.get(), GST_TAG_MERGE_APPEND, GST_TAG_TITLE, track->label().utf8().data(), nullptr); 60 61 if (track->type() == RealtimeMediaSource::Type::Audio) 62 gst_tag_list_add(tagList.get(), GST_TAG_MERGE_APPEND, WEBKIT_MEDIA_TRACK_TAG_KIND, static_cast<int>(AudioTrackPrivate::Kind::Main), nullptr); 63 else if (track->type() == RealtimeMediaSource::Type::Video) { 64 gst_tag_list_add(tagList.get(), GST_TAG_MERGE_APPEND, WEBKIT_MEDIA_TRACK_TAG_KIND, static_cast<int>(VideoTrackPrivate::Kind::Main), nullptr); 69 65 70 66 if (track->isCaptureTrack()) { 71 GStreamerVideoCaptureSource& source = static_cast<GStreamerVideoCaptureSource&>( 72 track->source()); 73 74 gst_tag_list_add(taglist, GST_TAG_MERGE_APPEND, 75 WEBKIT_MEDIA_TRACK_TAG_WIDTH, source.size().width(), 67 GStreamerVideoCaptureSource& source = static_cast<GStreamerVideoCaptureSource&>(track->source()); 68 gst_tag_list_add(tagList.get(), GST_TAG_MERGE_APPEND, WEBKIT_MEDIA_TRACK_TAG_WIDTH, source.size().width(), 76 69 WEBKIT_MEDIA_TRACK_TAG_HEIGHT, source.size().height(), nullptr); 77 70 } 78 71 } 79 72 80 return taglist; 73 GST_DEBUG("Track tags: %" GST_PTR_FORMAT, tagList.get()); 74 return tagList.leakRef(); 81 75 } 82 76 … … 94 88 } else { 95 89 GST_FIXME("Handle %d type", static_cast<int>(track->type())); 96 97 90 return nullptr; 98 91 } 99 92 100 auto gststream = (GstStream*)gst_stream_new(track->id().utf8().data(), 101 caps.get(), type, GST_STREAM_FLAG_SELECT); 102 auto tags = adoptGRef(mediaStreamTrackPrivateGetTags(track)); 103 gst_stream_set_tags(gststream, tags.get()); 104 105 return gststream; 93 auto* stream = gst_stream_new(track->id().utf8().data(), caps.get(), type, GST_STREAM_FLAG_SELECT); 94 auto tags = mediaStreamTrackPrivateGetTags(track); 95 gst_stream_set_tags(stream, tags.leakRef()); 96 return stream; 106 97 } 107 98 … … 113 104 public: 114 105 virtual ~WebKitMediaStreamTrackObserver() { }; 115 WebKitMediaStreamTrackObserver(WebKitMediaStreamSrc* src) 116 : m_mediaStreamSrc(src) 117 , m_enabled(true) { } 106 WebKitMediaStreamTrackObserver(GRefPtr<GstElement>&& src) 107 : m_src(WTFMove(src)) { } 118 108 void trackStarted(MediaStreamTrackPrivate&) final { }; 119 109 120 110 void trackEnded(MediaStreamTrackPrivate& track) final 121 111 { 122 webkitMediaStreamSrcTrackEnded(m_mediaStreamSrc, track); 112 if (m_src) 113 webkitMediaStreamSrcTrackEnded(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), track); 123 114 } 124 115 … … 134 125 void videoSampleAvailable(MediaSample& sample) final 135 126 { 136 if (!m_enabled )127 if (!m_enabled || !m_src) 137 128 return; 138 129 139 auto gstSample = static_cast<MediaSampleGStreamer*>(&sample)->platformSample().sample.gstSample;140 webkitMediaStreamSrcPushVideoSample( m_mediaStreamSrc, gstSample);130 auto* gstSample = static_cast<MediaSampleGStreamer*>(&sample)->platformSample().sample.gstSample; 131 webkitMediaStreamSrcPushVideoSample(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), gstSample); 141 132 } 142 133 143 134 void audioSamplesAvailable(const MediaTime&, const PlatformAudioData& audioData, const AudioStreamDescription&, size_t) final 144 135 { 145 if (!m_enabled )136 if (!m_enabled || !m_src) 146 137 return; 147 138 148 139 auto data = static_cast<const GStreamerAudioData&>(audioData); 149 webkitMediaStreamSrcPushAudioSample( m_mediaStreamSrc, data.getSample());140 webkitMediaStreamSrcPushAudioSample(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), data.getSample()); 150 141 } 151 142 152 143 private: 153 WebKitMediaStreamSrc* m_mediaStreamSrc;154 bool m_enabled ;144 GRefPtr<GstElement> m_src; 145 bool m_enabled { true }; 155 146 }; 156 147 157 class WebKitMediaStreamObserver 158 : public MediaStreamPrivate::Observer { 148 class WebKitMediaStreamObserver : public MediaStreamPrivate::Observer { 159 149 WTF_MAKE_FAST_ALLOCATED; 160 150 public: 161 151 virtual ~WebKitMediaStreamObserver() { }; 162 WebKitMediaStreamObserver(WebKitMediaStreamSrc* src) 163 : m_mediaStreamSrc(src) { } 164 165 void characteristicsChanged() final { GST_DEBUG_OBJECT(m_mediaStreamSrc, "renegotiation should happen"); } 152 WebKitMediaStreamObserver(GRefPtr<GstElement>&& src) 153 : m_src(WTFMove(src)) { } 154 155 void characteristicsChanged() final 156 { 157 if (m_src) 158 GST_DEBUG_OBJECT(m_src.get(), "renegotiation should happen"); 159 } 166 160 void activeStatusChanged() final { } 167 161 168 162 void didAddTrack(MediaStreamTrackPrivate& track) final 169 163 { 170 webkitMediaStreamSrcAddTrack(m_mediaStreamSrc, &track, false); 164 if (m_src) 165 webkitMediaStreamSrcAddTrack(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), &track, false); 171 166 } 172 167 173 168 void didRemoveTrack(MediaStreamTrackPrivate& track) final 174 169 { 175 webkitMediaStreamSrcRemoveTrackByType(m_mediaStreamSrc, track.type()); 170 if (m_src) 171 webkitMediaStreamSrcRemoveTrackByType(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), track.type()); 176 172 } 177 173 178 174 private: 179 WebKitMediaStreamSrc* m_mediaStreamSrc;175 GRefPtr<GstElement> m_src; 180 176 }; 181 177 182 typedef struct _WebKitMediaStreamSrcClass WebKitMediaStreamSrcClass; 183 struct _WebKitMediaStreamSrc { 184 GstBin parent_instance; 185 186 gchar* uri; 187 188 struct SourceData { 189 GRefPtr<GstElement> m_src; 190 void reset(bool isVideo) 191 { 192 m_firstBufferPts = GST_CLOCK_TIME_NONE; 193 m_isVideo = isVideo; 194 195 if (!m_src) 196 return; 197 178 class InternalSource { 179 WTF_MAKE_FAST_ALLOCATED; 180 public: 181 InternalSource(bool isCaptureTrack) 182 { 183 m_src = gst_element_factory_make("appsrc", nullptr); 184 RELEASE_ASSERT_WITH_MESSAGE(GST_IS_APP_SRC(m_src.get()), "GStreamer appsrc element not found. Please make sure to install gst-plugins-base"); 185 186 g_object_set(m_src.get(), "is-live", TRUE, "format", GST_FORMAT_TIME, "emit-signals", TRUE, "min-percent", 100, 187 "do-timestamp", isCaptureTrack, nullptr); 188 g_signal_connect(m_src.get(), "enough-data", G_CALLBACK(+[](GstElement*, InternalSource* data) { 189 data->m_enoughData = true; 190 }), this); 191 g_signal_connect(m_src.get(), "need-data", G_CALLBACK(+[](GstElement*, unsigned, InternalSource* data) { 192 data->m_enoughData = false; 193 }), this); 194 } 195 196 ~InternalSource() 197 { 198 g_signal_handlers_disconnect_matched(m_src.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this); 199 200 if (auto parent = adoptGRef(gst_object_get_parent(GST_OBJECT_CAST(m_src.get())))) { 201 GST_STATE_LOCK(GST_ELEMENT_CAST(parent.get())); 198 202 gst_element_set_locked_state(m_src.get(), true); 199 203 gst_element_set_state(m_src.get(), GST_STATE_NULL); 200 auto parent = adoptGRef(gst_object_get_parent(GST_OBJECT_CAST(m_src.get()))); 201 if (parent) 202 gst_bin_remove(GST_BIN_CAST(parent.get()), m_src.get()); 204 gst_bin_remove(GST_BIN_CAST(parent.get()), m_src.get()); 203 205 gst_element_set_locked_state(m_src.get(), false); 204 m_src = nullptr; 205 } 206 207 GstElement* src() 208 { 209 return m_src.get(); 210 } 211 212 static void needDataCallback(WebKitMediaStreamSrc::SourceData* self, unsigned) 213 { 214 self->setEnoughData(false); 215 } 216 217 static void enoughDataCallback(WebKitMediaStreamSrc::SourceData* self) 218 { 219 self->setEnoughData(true); 220 } 221 222 void ensureAppSrc() 223 { 224 ASSERT(!m_src); 225 m_src = gst_element_factory_make("appsrc", nullptr); 226 if (!GST_IS_APP_SRC(m_src.get())) 227 return; 228 229 g_object_set(m_src.get(), "is-live", true, "format", GST_FORMAT_TIME, "emit-signals", true, "min-percent", 100, nullptr); 230 g_signal_connect_swapped(m_src.get(), "enough-data", G_CALLBACK(enoughDataCallback), this); 231 g_signal_connect_swapped(m_src.get(), "need-data", G_CALLBACK(needDataCallback), this); 232 } 233 234 bool isUsed() 235 { 236 return !!m_src; 237 } 238 239 void setEnoughData(bool enough) 240 { 241 m_enoughData = enough; 242 } 243 244 void pushSample(GstSample *sample) 245 { 246 if (!m_src) 247 return; 248 249 bool drop = m_enoughData; 250 auto buffer = gst_sample_get_buffer(sample); 251 auto caps = gst_sample_get_caps(sample); 252 if (!GST_CLOCK_TIME_IS_VALID(m_firstBufferPts)) { 253 m_firstBufferPts = GST_BUFFER_PTS(buffer); 254 auto pad = adoptGRef(gst_element_get_static_pad(m_src.get(), "src")); 255 gst_pad_set_offset(pad.get(), -m_firstBufferPts); 256 } 257 258 if (m_isVideo && drop) { 259 drop = (gst_structure_has_name(gst_caps_get_structure(caps, 0), "video/x-raw") 260 || GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)); 261 } 262 263 if (drop) { 264 m_needsDiscont = true; 265 GST_INFO_OBJECT(m_src.get(), "%s queue full already... not pushing", m_isVideo ? "Video" : "Audio"); 266 return; 267 } 268 269 if (m_needsDiscont) { 270 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DISCONT); 271 m_needsDiscont = false; 272 } 273 274 gst_app_src_push_sample(GST_APP_SRC(m_src.get()), sample); 275 } 276 private: 277 GstClockTime m_firstBufferPts; 278 bool m_enoughData; 279 bool m_needsDiscont; 280 bool m_isVideo; 281 }; 282 283 SourceData audioSrc; 284 SourceData videoSrc; 285 206 GST_STATE_UNLOCK(GST_ELEMENT_CAST(parent.get())); 207 } 208 } 209 210 GstElement* get() const { return m_src.get(); } 211 212 void pushSample(GstSample* sample) 213 { 214 ASSERT(m_src); 215 if (!m_src) 216 return; 217 218 bool drop = m_enoughData; 219 auto* buffer = gst_sample_get_buffer(sample); 220 auto* caps = gst_sample_get_caps(sample); 221 if (!GST_CLOCK_TIME_IS_VALID(m_firstBufferPts)) { 222 m_firstBufferPts = GST_BUFFER_PTS(buffer); 223 auto pad = adoptGRef(gst_element_get_static_pad(m_src.get(), "src")); 224 gst_pad_set_offset(pad.get(), -m_firstBufferPts); 225 } 226 227 if (!m_isVideo) 228 m_isVideo = doCapsHaveType(caps, "video"); 229 230 if (*m_isVideo && drop) 231 drop = doCapsHaveType(caps, "video/x-raw") || GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); 232 233 if (drop) { 234 m_needsDiscont = true; 235 GST_INFO_OBJECT(m_src.get(), "%s queue full already... not pushing", *m_isVideo ? "Video" : "Audio"); 236 return; 237 } 238 239 if (m_needsDiscont) { 240 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DISCONT); 241 m_needsDiscont = false; 242 } 243 244 gst_app_src_push_sample(GST_APP_SRC(m_src.get()), sample); 245 } 246 247 private: 248 GRefPtr<GstElement> m_src; 249 GstClockTime m_firstBufferPts { GST_CLOCK_TIME_NONE }; 250 bool m_enoughData { false }; 251 bool m_needsDiscont { false }; 252 Optional<bool> m_isVideo; 253 }; 254 255 struct _WebKitMediaStreamSrcPrivate { 256 CString uri; 257 Optional<InternalSource> audioSrc; 258 Optional<InternalSource> videoSrc; 286 259 std::unique_ptr<WebKitMediaStreamTrackObserver> mediaStreamTrackObserver; 287 260 std::unique_ptr<WebKitMediaStreamObserver> mediaStreamObserver; 288 volatile gint npads;289 261 RefPtr<MediaStreamPrivate> stream; 290 262 RefPtr<MediaStreamTrackPrivate> track; 291 292 GstFlowCombiner* flowCombiner; 263 GUniquePtr<GstFlowCombiner> flowCombiner; 293 264 GRefPtr<GstStreamCollection> streamCollection; 294 };295 296 struct _WebKitMediaStreamSrcClass {297 GstBinClass parent_class;298 265 }; 299 266 … … 304 271 }; 305 272 306 static GstURIType webkit _media_stream_src_uri_get_type(GType)273 static GstURIType webkitMediaStreamSrcUriGetType(GType) 307 274 { 308 275 return GST_URI_SRC; 309 276 } 310 277 311 static const gchar* const* webkit_media_stream_src_uri_get_protocols(GType) 312 { 313 static const gchar* protocols[] = { "mediastream", nullptr }; 314 278 static const char* const* webkitMediaStreamSrcUriGetProtocols(GType) 279 { 280 static const char* protocols[] = { "mediastream", nullptr }; 315 281 return protocols; 316 282 } 317 283 318 static gchar* webkit_media_stream_src_uri_get_uri(GstURIHandler* handler)284 static char* webkitMediaStreamSrcUriGetUri(GstURIHandler* handler) 319 285 { 320 286 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(handler); 321 322 /* FIXME: make thread-safe */ 323 return g_strdup(self->uri); 324 } 325 326 static gboolean webkitMediaStreamSrcUriSetUri(GstURIHandler* handler, const gchar* uri, 327 GError**) 287 return g_strdup(self->priv->uri.data()); 288 } 289 290 static gboolean webkitMediaStreamSrcUriSetUri(GstURIHandler* handler, const char* uri, GError**) 328 291 { 329 292 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(handler); 330 self->uri = g_strdup(uri); 331 293 self->priv->uri = CString(uri); 332 294 return TRUE; 333 295 } 334 296 335 static void webkitMediaStreamSrcUriHandlerInit(gpointer g_iface, gpointer) 336 { 337 GstURIHandlerInterface* iface = (GstURIHandlerInterface*)g_iface; 338 339 iface->get_type = webkit_media_stream_src_uri_get_type; 340 iface->get_protocols = webkit_media_stream_src_uri_get_protocols; 341 iface->get_uri = webkit_media_stream_src_uri_get_uri; 297 static void webkitMediaStreamSrcUriHandlerInit(gpointer gIface, gpointer) 298 { 299 auto* iface = static_cast<GstURIHandlerInterface*>(gIface); 300 iface->get_type = webkitMediaStreamSrcUriGetType; 301 iface->get_protocols = webkitMediaStreamSrcUriGetProtocols; 302 iface->get_uri = webkitMediaStreamSrcUriGetUri; 342 303 iface->set_uri = webkitMediaStreamSrcUriSetUri; 343 304 } … … 346 307 #define GST_CAT_DEFAULT webkitMediaStreamSrcDebug 347 308 348 #define doInit \349 G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webkitMediaStreamSrcUriHandlerInit); \350 GST_DEBUG_CATEGORY_INIT(webkitMediaStreamSrcDebug, "webkit webmediastreamsrc", 0, "mediastreamsrc element");\351 gst_tag_register_static(WEBKIT_MEDIA_TRACK_TAG_WIDTH, GST_TAG_FLAG_META, G_TYPE_INT, "Webkit MediaStream width", "Webkit MediaStream width", gst_tag_merge_use_first); \309 #define doInit \ 310 G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webkitMediaStreamSrcUriHandlerInit); \ 311 GST_DEBUG_CATEGORY_INIT(webkitMediaStreamSrcDebug, "webkitmediastreamsrc", 0, "mediastreamsrc element"); \ 312 gst_tag_register_static(WEBKIT_MEDIA_TRACK_TAG_WIDTH, GST_TAG_FLAG_META, G_TYPE_INT, "Webkit MediaStream width", "Webkit MediaStream width", gst_tag_merge_use_first); \ 352 313 gst_tag_register_static(WEBKIT_MEDIA_TRACK_TAG_HEIGHT, GST_TAG_FLAG_META, G_TYPE_INT, "Webkit MediaStream height", "Webkit MediaStream height", gst_tag_merge_use_first); \ 353 314 gst_tag_register_static(WEBKIT_MEDIA_TRACK_TAG_KIND, GST_TAG_FLAG_META, G_TYPE_INT, "Webkit MediaStream Kind", "Webkit MediaStream Kind", gst_tag_merge_use_first); 354 315 355 G_DEFINE_TYPE_WITH_CODE(WebKitMediaStreamSrc, webkit_media_stream_src, GST_TYPE_BIN, doInit); 356 357 static void webkitMediaStreamSrcSetProperty(GObject* object, guint prop_id, 358 const GValue*, GParamSpec* pspec)359 { 360 switch (prop _id) {316 #define webkit_media_stream_src_parent_class parent_class 317 WEBKIT_DEFINE_TYPE_WITH_CODE(WebKitMediaStreamSrc, webkit_media_stream_src, GST_TYPE_BIN, doInit) 318 319 static void webkitMediaStreamSrcSetProperty(GObject* object, guint propertyId, const GValue*, GParamSpec* pspec) 320 { 321 switch (propertyId) { 361 322 default: 362 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop _id, pspec);323 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec); 363 324 break; 364 325 } 365 326 } 366 327 367 static void webkitMediaStreamSrcGetProperty(GObject* object, guint prop_id, GValue* value, 368 GParamSpec* pspec) 369 { 370 switch (prop_id) { 328 static void webkitMediaStreamSrcGetProperty(GObject* object, guint propertyId, GValue* value, GParamSpec* pspec) 329 { 330 switch (propertyId) { 371 331 case PROP_IS_LIVE: 372 332 g_value_set_boolean(value, TRUE); 373 333 break; 374 334 default: 375 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop _id, pspec);335 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec); 376 336 break; 377 337 } 378 338 } 379 339 380 static void webkitMediaStreamSrcDispose(GObject* object) 381 { 340 static void webkitMediaStreamSrcConstructed(GObject* object) 341 { 342 GST_CALL_PARENT(G_OBJECT_CLASS, constructed, (object)); 382 343 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(object); 383 384 self->audioSrc.reset(false); 385 self->videoSrc.reset(true); 344 auto* priv = self->priv; 345 346 priv->mediaStreamTrackObserver = makeUnique<WebKitMediaStreamTrackObserver>(GST_ELEMENT_CAST(gst_object_ref(self))); 347 priv->mediaStreamObserver = makeUnique<WebKitMediaStreamObserver>(GST_ELEMENT_CAST(gst_object_ref(self))); 348 priv->flowCombiner = GUniquePtr<GstFlowCombiner>(gst_flow_combiner_new()); 349 } 350 351 static void stopObservingTracks(WebKitMediaStreamSrc* self) 352 { 353 GST_OBJECT_LOCK(self); 354 auto* priv = self->priv; 355 if (priv->stream) { 356 for (auto& track : priv->stream->tracks()) { 357 track->source().removeAudioSampleObserver(*priv->mediaStreamTrackObserver); 358 track->source().removeVideoSampleObserver(*priv->mediaStreamTrackObserver); 359 track->removeObserver(*priv->mediaStreamTrackObserver); 360 } 361 } else if (priv->track) { 362 priv->track->source().removeAudioSampleObserver(*priv->mediaStreamTrackObserver); 363 priv->track->source().removeVideoSampleObserver(*priv->mediaStreamTrackObserver); 364 priv->track->removeObserver(*priv->mediaStreamTrackObserver); 365 } 366 GST_OBJECT_UNLOCK(self); 386 367 } 387 368 … … 390 371 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(object); 391 372 373 stopObservingTracks(self); 374 392 375 GST_OBJECT_LOCK(self); 393 if (self->stream) { 394 for (auto& track : self->stream->tracks()) { 395 track->source().removeAudioSampleObserver(*self->mediaStreamTrackObserver.get()); 396 track->source().removeVideoSampleObserver(*self->mediaStreamTrackObserver.get()); 397 track->removeObserver(*self->mediaStreamTrackObserver.get()); 398 } 399 self->stream->removeObserver(*self->mediaStreamObserver); 400 self->stream = nullptr; 376 auto* priv = self->priv; 377 if (priv->stream) { 378 priv->stream->removeObserver(*priv->mediaStreamObserver); 379 priv->stream = nullptr; 401 380 } 402 381 GST_OBJECT_UNLOCK(self); 403 404 g_clear_pointer(&self->uri, g_free);405 gst_flow_combiner_free(self->flowCombiner);406 382 } 407 383 408 384 static GstStateChangeReturn webkitMediaStreamSrcChangeState(GstElement* element, GstStateChange transition) 409 385 { 410 GstStateChangeReturn result; 411 auto* self = WEBKIT_MEDIA_STREAM_SRC(element); 412 413 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) { 414 415 GST_OBJECT_LOCK(self); 416 if (self->stream) { 417 for (auto& track : self->stream->tracks()) { 418 track->source().removeAudioSampleObserver(*self->mediaStreamTrackObserver.get()); 419 track->source().removeVideoSampleObserver(*self->mediaStreamTrackObserver.get()); 420 track->removeObserver(*self->mediaStreamTrackObserver.get()); 421 } 422 } else if (self->track) { 423 self->track->source().removeAudioSampleObserver(*self->mediaStreamTrackObserver.get()); 424 self->track->source().removeVideoSampleObserver(*self->mediaStreamTrackObserver.get()); 425 self->track->removeObserver(*self->mediaStreamTrackObserver.get()); 426 } 427 GST_OBJECT_UNLOCK(self); 428 } 429 430 result = GST_ELEMENT_CLASS(webkit_media_stream_src_parent_class)->change_state(element, transition); 386 #if GST_CHECK_VERSION(1, 14, 0) 387 GST_DEBUG_OBJECT(element, "%s", gst_state_change_get_name(transition)); 388 #endif 389 390 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) 391 stopObservingTracks(WEBKIT_MEDIA_STREAM_SRC(element)); 392 393 GstStateChangeReturn result = GST_ELEMENT_CLASS(webkit_media_stream_src_parent_class)->change_state(element, transition); 431 394 432 395 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) … … 438 401 static void webkit_media_stream_src_class_init(WebKitMediaStreamSrcClass* klass) 439 402 { 440 GObjectClass* gobject_class = G_OBJECT_CLASS(klass); 441 GstElementClass* gstelement_klass = GST_ELEMENT_CLASS(klass); 442 443 gobject_class->finalize = webkitMediaStreamSrcFinalize; 444 gobject_class->dispose = webkitMediaStreamSrcDispose; 445 gobject_class->get_property = webkitMediaStreamSrcGetProperty; 446 gobject_class->set_property = webkitMediaStreamSrcSetProperty; 447 448 g_object_class_install_property(gobject_class, PROP_IS_LIVE, 449 g_param_spec_boolean("is-live", "Is Live", 450 "Let playbin3 know we are a live source.", 451 TRUE, (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); 452 453 gstelement_klass->change_state = webkitMediaStreamSrcChangeState; 454 gst_element_class_add_pad_template(gstelement_klass, 455 gst_static_pad_template_get(&videoSrcTemplate)); 456 gst_element_class_add_pad_template(gstelement_klass, 457 gst_static_pad_template_get(&audioSrcTemplate)); 458 } 459 460 static void webkit_media_stream_src_init(WebKitMediaStreamSrc* self) 461 { 462 self->mediaStreamTrackObserver = makeUnique<WebKitMediaStreamTrackObserver>(self); 463 self->mediaStreamObserver = makeUnique<WebKitMediaStreamObserver>(self); 464 self->flowCombiner = gst_flow_combiner_new(); 465 self->videoSrc.reset(true); 466 self->audioSrc.reset(false); 467 } 468 469 typedef struct { 470 WebKitMediaStreamSrc* self; 403 GObjectClass* gobjectClass = G_OBJECT_CLASS(klass); 404 GstElementClass* gstElementClass = GST_ELEMENT_CLASS(klass); 405 406 gobjectClass->constructed = webkitMediaStreamSrcConstructed; 407 gobjectClass->finalize = webkitMediaStreamSrcFinalize; 408 gobjectClass->get_property = webkitMediaStreamSrcGetProperty; 409 gobjectClass->set_property = webkitMediaStreamSrcSetProperty; 410 411 g_object_class_install_property(gobjectClass, PROP_IS_LIVE, g_param_spec_boolean("is-live", "Is Live", "Let playbin3 know we are a live source.", 412 TRUE, static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); 413 414 gstElementClass->change_state = GST_DEBUG_FUNCPTR(webkitMediaStreamSrcChangeState); 415 gst_element_class_add_pad_template(gstElementClass, gst_static_pad_template_get(&videoSrcTemplate)); 416 gst_element_class_add_pad_template(gstElementClass, gst_static_pad_template_get(&audioSrcTemplate)); 417 } 418 419 static GstFlowReturn webkitMediaStreamSrcChain(GstPad* pad, GstObject* parent, GstBuffer* buffer) 420 { 421 GRefPtr<GstElement> element = adoptGRef(GST_ELEMENT_CAST(gst_object_get_parent(parent))); 422 GstFlowReturn chainResult = gst_proxy_pad_chain_default(pad, GST_OBJECT_CAST(element.get()), buffer); 423 auto* self = WEBKIT_MEDIA_STREAM_SRC(element.get()); 424 GstFlowReturn result = gst_flow_combiner_update_pad_flow(self->priv->flowCombiner.get(), pad, chainResult); 425 426 if (result == GST_FLOW_FLUSHING) 427 return chainResult; 428 429 return result; 430 } 431 432 static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* padTemplate, MediaStreamTrackPrivate* track) 433 { 434 GST_DEBUG_OBJECT(self, "%s Ghosting %" GST_PTR_FORMAT, gst_object_get_path_string(GST_OBJECT_CAST(self)), target); 435 436 static Atomic<uint32_t> nextPadId; 437 auto padName = makeString("src_", nextPadId.exchangeAdd(1)); 438 auto* ghostPad = webkitGstGhostPadFromStaticTemplate(padTemplate, padName.utf8().data(), target); 439 gst_pad_set_active(ghostPad, TRUE); 440 gst_element_add_pad(GST_ELEMENT_CAST(self), ghostPad); 441 442 auto proxyPad = adoptGRef(GST_PAD(gst_proxy_pad_get_internal(GST_PROXY_PAD(ghostPad)))); 443 gst_flow_combiner_add_pad(self->priv->flowCombiner.get(), proxyPad.get()); 444 gst_pad_set_chain_function(proxyPad.get(), static_cast<GstPadChainFunction>(webkitMediaStreamSrcChain)); 445 446 auto tags = mediaStreamTrackPrivateGetTags(track); 447 gst_pad_push_event(target, gst_event_new_tag(tags.leakRef())); 448 } 449 450 struct ProbeData { 451 WTF_MAKE_STRUCT_FAST_ALLOCATED; 452 ProbeData(GstElement* element, GstStaticPadTemplate* padTemplate, RefPtr<MediaStreamTrackPrivate> track) 453 : element(element) 454 , padTemplate(padTemplate) 455 , track(track) { } 456 457 GRefPtr<GstElement> element; 458 GstStaticPadTemplate* padTemplate; 471 459 RefPtr<MediaStreamTrackPrivate> track; 472 GstStaticPadTemplate* pad_template; 473 } ProbeData; 474 475 static GstFlowReturn webkitMediaStreamSrcChain(GstPad* pad, GstObject* parent, GstBuffer* buffer) 476 { 477 GstFlowReturn result, chain_result; 478 GRefPtr<WebKitMediaStreamSrc> self = adoptGRef(WEBKIT_MEDIA_STREAM_SRC(gst_object_get_parent(parent))); 479 480 chain_result = gst_proxy_pad_chain_default(pad, GST_OBJECT(self.get()), buffer); 481 result = gst_flow_combiner_update_pad_flow(self.get()->flowCombiner, pad, chain_result); 482 483 if (result == GST_FLOW_FLUSHING) 484 return chain_result; 485 486 return result; 487 } 488 489 static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* pad_template) 490 { 491 auto padname = makeString("src_", g_atomic_int_add(&(self->npads), 1)); 492 auto ghostpad = gst_ghost_pad_new_from_template(padname.utf8().data(), target, 493 gst_static_pad_template_get(pad_template)); 494 495 GST_DEBUG_OBJECT(self, "%s Ghosting %" GST_PTR_FORMAT, 496 gst_object_get_path_string(GST_OBJECT_CAST(self)), 497 target); 498 499 auto proxypad = adoptGRef(GST_PAD(gst_proxy_pad_get_internal(GST_PROXY_PAD(ghostpad)))); 500 gst_pad_set_active(ghostpad, TRUE); 501 if (!gst_element_add_pad(GST_ELEMENT(self), GST_PAD(ghostpad))) { 502 GST_ERROR_OBJECT(self, "Could not add pad %s:%s", GST_DEBUG_PAD_NAME(ghostpad)); 503 ASSERT_NOT_REACHED(); 504 505 return; 506 } 507 508 gst_flow_combiner_add_pad(self->flowCombiner, proxypad.get()); 509 gst_pad_set_chain_function(proxypad.get(), 510 static_cast<GstPadChainFunction>(webkitMediaStreamSrcChain)); 511 } 460 }; 512 461 513 462 static GstPadProbeReturn webkitMediaStreamSrcPadProbeCb(GstPad* pad, GstPadProbeInfo* info, ProbeData* data) 514 463 { 515 464 GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info); 516 WebKitMediaStreamSrc* self = data->self; 517 465 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(data->element.get()); 466 467 GST_DEBUG_OBJECT(self, "Event %" GST_PTR_FORMAT, event); 518 468 switch (GST_EVENT_TYPE(event)) { 519 469 case GST_EVENT_STREAM_START: { 520 const gchar* stream_id; 521 GRefPtr<GstStream> stream = nullptr; 522 523 gst_event_parse_stream_start(event, &stream_id); 524 if (!g_strcmp0(stream_id, data->track->id().utf8().data())) { 470 const char* streamId; 471 gst_event_parse_stream_start(event, &streamId); 472 if (!g_strcmp0(streamId, data->track->id().utf8().data())) { 525 473 GST_INFO_OBJECT(pad, "Event has been sticked already"); 526 return GST_PAD_PROBE_OK; 527 } 528 529 auto stream_start = gst_event_new_stream_start(data->track->id().utf8().data()); 530 gst_event_set_group_id(stream_start, 1); 531 gst_event_unref(event); 532 533 gst_pad_push_event(pad, stream_start); 534 gst_pad_push_event(pad, gst_event_new_tag(mediaStreamTrackPrivateGetTags(data->track.get()))); 535 536 webkitMediaStreamSrcAddPad(self, pad, data->pad_template); 537 538 return GST_PAD_PROBE_HANDLED; 474 return GST_PAD_PROBE_REMOVE; 475 } 476 477 auto* streamStart = gst_event_new_stream_start(data->track->id().utf8().data()); 478 gst_event_set_group_id(streamStart, 1); 479 gst_pad_push_event(pad, streamStart); 480 481 webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, data->track.get()); 482 return GST_PAD_PROBE_REMOVE; 539 483 } 540 484 default: … … 545 489 } 546 490 547 static gboolean webkitMediaStreamSrcSetupSrc(WebKitMediaStreamSrc* self,548 MediaStreamTrackPrivate* track, GstElement* element, 549 G stStaticPadTemplate* pad_template, gboolean observe_track,550 bool onlyTrack)551 { 491 static void webkitMediaStreamSrcSetupSrc(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, GstElement* element, GstStaticPadTemplate* padTemplate, bool onlyTrack) 492 { 493 GST_DEBUG_OBJECT(self, "Setup source %" GST_PTR_FORMAT ", only track: %s", element, boolForPrinting(onlyTrack)); 494 gst_bin_add(GST_BIN_CAST(self), element); 495 552 496 auto pad = adoptGRef(gst_element_get_static_pad(element, "src")); 553 554 gst_bin_add(GST_BIN(self), element);555 556 497 if (!onlyTrack) { 557 ProbeData* data = new ProbeData; 558 data->self = WEBKIT_MEDIA_STREAM_SRC(self); 559 data->pad_template = pad_template; 560 data->track = track; 561 562 gst_pad_add_probe(pad.get(), (GstPadProbeType)GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, 563 (GstPadProbeCallback)webkitMediaStreamSrcPadProbeCb, data, 564 [](gpointer data) { 565 delete (ProbeData*)data; 566 }); 498 auto* data = new ProbeData(GST_ELEMENT_CAST(self), padTemplate, track); 499 gst_pad_add_probe(pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, reinterpret_cast<GstPadProbeCallback>(webkitMediaStreamSrcPadProbeCb), data, [](gpointer data) { 500 delete reinterpret_cast<ProbeData*>(data); 501 }); 502 } else { 503 gst_pad_set_active(pad.get(), TRUE); 504 webkitMediaStreamSrcAddPad(self, pad.get(), padTemplate, track); 505 } 506 507 auto* priv = self->priv; 508 track->addObserver(*priv->mediaStreamTrackObserver.get()); 509 auto& source = track->source(); 510 switch (source.type()) { 511 case RealtimeMediaSource::Type::Audio: 512 source.addAudioSampleObserver(*priv->mediaStreamTrackObserver); 513 break; 514 case RealtimeMediaSource::Type::Video: 515 source.addVideoSampleObserver(*priv->mediaStreamTrackObserver); 516 break; 517 case RealtimeMediaSource::Type::None: 518 ASSERT_NOT_REACHED(); 519 } 520 521 gst_element_sync_state_with_parent(element); 522 } 523 524 static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc* self) 525 { 526 auto* priv = self->priv; 527 ASSERT(priv->stream); 528 GST_OBJECT_LOCK(self); 529 priv->streamCollection = adoptGRef(gst_stream_collection_new(priv->stream->id().utf8().data())); 530 for (auto& track : priv->stream->tracks()) 531 gst_stream_collection_add_stream(priv->streamCollection.get(), webkitMediaStreamNew(track.get())); 532 533 if (priv->track) 534 gst_stream_collection_add_stream(priv->streamCollection.get(), webkitMediaStreamNew(priv->track.get())); 535 GST_OBJECT_UNLOCK(self); 536 537 GST_DEBUG_OBJECT(self, "Posting stream collection"); 538 gst_element_post_message(GST_ELEMENT_CAST(self), gst_message_new_stream_collection(GST_OBJECT_CAST(self), priv->streamCollection.get())); 539 } 540 541 void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, bool onlyTrack) 542 { 543 auto* priv = self->priv; 544 if (track->type() == RealtimeMediaSource::Type::Audio) { 545 priv->audioSrc.emplace(track->isCaptureTrack()); 546 webkitMediaStreamSrcSetupSrc(self, track, priv->audioSrc->get(), &audioSrcTemplate, onlyTrack); 547 } else if (track->type() == RealtimeMediaSource::Type::Video) { 548 priv->videoSrc.emplace(track->isCaptureTrack()); 549 webkitMediaStreamSrcSetupSrc(self, track, priv->videoSrc->get(), &videoSrcTemplate, onlyTrack); 567 550 } else 568 webkitMediaStreamSrcAddPad(self, pad.get(), pad_template); 569 570 if (observe_track) { 571 track->addObserver(*self->mediaStreamTrackObserver.get()); 572 auto& source = track->source(); 573 switch (source.type()) { 574 case RealtimeMediaSource::Type::Audio: 575 source.addAudioSampleObserver(*self->mediaStreamTrackObserver.get()); 576 break; 577 case RealtimeMediaSource::Type::Video: 578 source.addVideoSampleObserver(*self->mediaStreamTrackObserver.get()); 579 break; 580 case RealtimeMediaSource::Type::None: 581 ASSERT_NOT_REACHED(); 582 } 583 } 584 gst_element_sync_state_with_parent(element); 585 return TRUE; 586 } 587 588 static gboolean webkitMediaStreamSrcSetupAppSrc(WebKitMediaStreamSrc* self, 589 MediaStreamTrackPrivate* track, WebKitMediaStreamSrc::SourceData* data, 590 GstStaticPadTemplate* pad_template, bool onlyTrack) 591 { 592 data->ensureAppSrc(); 593 if (track->isCaptureTrack()) 594 g_object_set(data->src(), "do-timestamp", true, nullptr); 595 596 return webkitMediaStreamSrcSetupSrc(self, track, data->src(), pad_template, TRUE, onlyTrack); 597 } 598 599 static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc* self, MediaStreamPrivate* stream) 600 { 551 GST_INFO_OBJECT(self, "Unsupported track type: %d", static_cast<int>(track->type())); 552 553 if ((priv->videoSrc || priv->audioSrc) && onlyTrack) 554 self->priv->track = track; 555 } 556 557 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc* self, RealtimeMediaSource::Type trackType) 558 { 559 if (trackType == RealtimeMediaSource::Type::Audio) 560 self->priv->audioSrc.reset(); 561 else if (trackType == RealtimeMediaSource::Type::Video) 562 self->priv->videoSrc.reset(); 563 else 564 GST_INFO_OBJECT(self, "Unsupported track type: %d", static_cast<int>(trackType)); 565 } 566 567 void webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc* self, MediaStreamPrivate* stream) 568 { 569 ASSERT(WEBKIT_IS_MEDIA_STREAM_SRC(self)); 570 ASSERT(!self->priv->stream); 571 self->priv->stream = stream; 572 webkitMediaStreamSrcPostStreamCollection(self); 573 574 self->priv->stream->addObserver(*self->priv->mediaStreamObserver.get()); 575 auto tracks = stream->tracks(); 576 bool onlyTrack = tracks.size() == 1; 577 for (auto& track : tracks) 578 webkitMediaStreamSrcAddTrack(self, track.get(), onlyTrack); 579 } 580 581 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc* self, GstSample* sample) 582 { 583 if (self->priv->videoSrc) 584 self->priv->videoSrc->pushSample(sample); 585 } 586 587 static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc* self, GstSample* sample) 588 { 589 if (self->priv->audioSrc) 590 self->priv->audioSrc->pushSample(sample); 591 } 592 593 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate& track) 594 { 595 GRefPtr<GstPad> pad; 596 597 GST_DEBUG_OBJECT(self, "Track %s ended", track.label().utf8().data()); 601 598 GST_OBJECT_LOCK(self); 602 self->streamCollection = adoptGRef(gst_stream_collection_new(stream->id().utf8().data())); 603 for (auto& track : stream->tracks()) { 604 auto gststream = webkitMediaStreamNew(track.get()); 605 606 gst_stream_collection_add_stream(self->streamCollection.get(), gststream); 607 } 608 GST_OBJECT_UNLOCK(self); 609 610 gst_element_post_message(GST_ELEMENT(self), 611 gst_message_new_stream_collection(GST_OBJECT(self), self->streamCollection.get())); 612 } 613 614 bool webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, bool onlyTrack) 615 { 616 bool res = false; 617 if (track->type() == RealtimeMediaSource::Type::Audio) 618 res = webkitMediaStreamSrcSetupAppSrc(self, track, &self->audioSrc, &audioSrcTemplate, onlyTrack); 619 else if (track->type() == RealtimeMediaSource::Type::Video) 620 res = webkitMediaStreamSrcSetupAppSrc(self, track, &self->videoSrc, &videoSrcTemplate, onlyTrack); 621 else 622 GST_INFO("Unsupported track type: %d", static_cast<int>(track->type())); 623 624 if (onlyTrack && res) 625 self->track = track; 626 627 return false; 628 } 629 630 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc* self, RealtimeMediaSource::Type trackType) 631 { 632 if (trackType == RealtimeMediaSource::Type::Audio) 633 self->audioSrc.reset(false); 634 else if (trackType == RealtimeMediaSource::Type::Video) 635 self->videoSrc.reset(true); 636 else 637 GST_INFO("Unsupported track type: %d", static_cast<int>(trackType)); 638 } 639 640 bool webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc* self, MediaStreamPrivate* stream) 641 { 642 ASSERT(WEBKIT_IS_MEDIA_STREAM_SRC(self)); 643 644 webkitMediaStreamSrcRemoveTrackByType(self, RealtimeMediaSource::Type::Audio); 645 webkitMediaStreamSrcRemoveTrackByType(self, RealtimeMediaSource::Type::Video); 646 647 webkitMediaStreamSrcPostStreamCollection(self, stream); 648 649 self->stream = stream; 650 self->stream->addObserver(*self->mediaStreamObserver.get()); 651 for (auto& track : stream->tracks()) 652 webkitMediaStreamSrcAddTrack(self, track.get(), false); 653 654 return TRUE; 655 } 656 657 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc* self, GstSample* gstsample) 658 { 659 self->videoSrc.pushSample(gstsample); 660 } 661 662 static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc* self, GstSample* gstsample) 663 { 664 self->audioSrc.pushSample(gstsample); 665 } 666 667 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, 668 MediaStreamTrackPrivate& track) 669 { 670 GRefPtr<GstPad> pad = nullptr; 671 672 GST_OBJECT_LOCK(self); 673 for (auto tmp = GST_ELEMENT(self)->srcpads; tmp; tmp = tmp->next) { 674 GstPad* tmppad = GST_PAD(tmp->data); 675 const gchar* stream_id; 676 677 GstEvent* stream_start = gst_pad_get_sticky_event(tmppad, GST_EVENT_STREAM_START, 0); 678 if (!stream_start) 599 for (auto* item = GST_ELEMENT_CAST(self)->srcpads; item; item = item->next) { 600 auto* currentPad = GST_PAD_CAST(item->data); 601 auto streamStart = adoptGRef(gst_pad_get_sticky_event(currentPad, GST_EVENT_STREAM_START, 0)); 602 if (!streamStart) 679 603 continue; 680 604 681 gst_event_parse_stream_start(stream_start, &stream_id); 682 if (String(stream_id) == track.id()) { 683 pad = tmppad; 605 const char* streamId; 606 gst_event_parse_stream_start(streamStart.get(), &streamId); 607 if (!g_strcmp0(streamId, track.id().utf8().data())) { 608 pad = currentPad; 684 609 break; 685 610 } … … 689 614 if (!pad) { 690 615 GST_ERROR_OBJECT(self, "No pad found for %s", track.id().utf8().data()); 691 692 616 return; 693 617 } 694 618 695 619 // Make sure that the video.videoWidth is reset to 0 696 webkitMediaStreamSrcPostStreamCollection(self , self->stream.get());620 webkitMediaStreamSrcPostStreamCollection(self); 697 621 auto tags = mediaStreamTrackPrivateGetTags(&track); 698 gst_pad_push_event(pad.get(), gst_event_new_tag(tags ));622 gst_pad_push_event(pad.get(), gst_event_new_tag(tags.leakRef())); 699 623 gst_pad_push_event(pad.get(), gst_event_new_eos()); 700 624 } 701 625 702 GstElement* webkitMediaStreamSrcNew(void) 703 { 704 return GST_ELEMENT(g_object_new(webkit_media_stream_src_get_type(), nullptr)); 705 } 706 707 } // WebCore 708 709 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) 626 GstElement* webkitMediaStreamSrcNew() 627 { 628 return GST_ELEMENT_CAST(g_object_new(webkit_media_stream_src_get_type(), nullptr)); 629 } 630 631 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER) -
trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.h
r238951 r263836 22 22 #pragma once 23 23 24 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) 25 26 #include "MediaStreamPrivate.h" 27 #include "MediaStreamTrackPrivate.h" 24 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER) 28 25 29 26 #include <gst/gst.h> 27 28 namespace WebCore { 29 class MediaStreamPrivate; 30 class MediaStreamTrackPrivate; 31 } 32 33 G_BEGIN_DECLS 30 34 31 35 #define WEBKIT_MEDIA_TRACK_TAG_WIDTH "webkit-media-stream-width" … … 33 37 #define WEBKIT_MEDIA_TRACK_TAG_KIND "webkit-media-stream-kind" 34 38 35 namespace WebCore {36 37 typedef struct _WebKitMediaStreamSrc WebKitMediaStreamSrc;38 39 39 #define WEBKIT_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_CAST((o), WEBKIT_TYPE_MEDIA_STREAM_SRC, WebKitMediaStreamSrc)) 40 40 #define WEBKIT_IS_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), WEBKIT_TYPE_MEDIA_STREAM_SRC)) 41 41 #define WEBKIT_TYPE_MEDIA_STREAM_SRC (webkit_media_stream_src_get_type()) 42 GType webkit_media_stream_src_get_type(void) G_GNUC_CONST; 43 bool webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc*, MediaStreamPrivate*); 44 bool webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc*, MediaStreamTrackPrivate*, bool onlyTrack); 45 GstElement * webkitMediaStreamSrcNew(void); 46 } // WebCore 42 GType webkit_media_stream_src_get_type(void); 47 43 48 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) 44 typedef struct _WebKitMediaStreamSrc WebKitMediaStreamSrc; 45 typedef struct _WebKitMediaStreamSrcClass WebKitMediaStreamSrcClass; 46 typedef struct _WebKitMediaStreamSrcPrivate WebKitMediaStreamSrcPrivate; 47 48 struct _WebKitMediaStreamSrc { 49 GstBin parent; 50 WebKitMediaStreamSrcPrivate* priv; 51 }; 52 53 struct _WebKitMediaStreamSrcClass { 54 GstBinClass parentClass; 55 }; 56 57 void webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc*, WebCore::MediaStreamPrivate*); 58 void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc*, WebCore::MediaStreamTrackPrivate*, bool onlyTrack); 59 GstElement* webkitMediaStreamSrcNew(); 60 61 G_END_DECLS 62 63 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
Note:
See TracChangeset
for help on using the changeset viewer.