⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 263836 in webkit


Ignore:
Timestamp:
Jul 2, 2020, 1:20:51 AM (6 years ago)
Author:
Philippe Normand
Message:

[GStreamer] Rewrite mediastreamsrc element
https://bugs.webkit.org/show_bug.cgi?id=213777

Reviewed by Xabier Rodriguez-Calvar.

The underlying functionality remains the same, design-wise. This is mostly a refactoring
switching to smart pointers as much as possible and trying to comply with WebKit code style
guidelines.

The previous version of this element was leaking pad templates and sticky stream-start
events (in webkitMediaStreamSrcTrackEnded).

The LIBWEBRTC ifdef guards were removed as well, because there's no actual libwebrtc
dependency involved in this code.

No new tests, existing webrtc and fast/mediastream tests cover this patch.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
  • platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:

(mediaStreamTrackPrivateGetTags):
(webkitMediaStreamNew):
(WebKitMediaStreamTrackObserver::WebKitMediaStreamTrackObserver):
(WebKitMediaStreamObserver::WebKitMediaStreamObserver):
(InternalSource::InternalSource):
(InternalSource::~InternalSource):
(InternalSource::src const):
(InternalSource::pushSample):
(webkitMediaStreamSrcUriGetType):
(webkitMediaStreamSrcUriGetProtocols):
(webkitMediaStreamSrcUriGetUri):
(webkitMediaStreamSrcUriSetUri):
(webkitMediaStreamSrcUriHandlerInit):
(webkitMediaStreamSrcSetProperty):
(webkitMediaStreamSrcGetProperty):
(webkitMediaStreamSrcConstructed):
(stopObservingTracks):
(webkitMediaStreamSrcFinalize):
(webkitMediaStreamSrcChangeState):
(webkit_media_stream_src_class_init):
(webkitMediaStreamSrcChain):
(webkitMediaStreamSrcAddPad):
(ProbeData::ProbeData):
(webkitMediaStreamSrcPadProbeCb):
(webkitMediaStreamSrcSetupSrc):
(webkitMediaStreamSrcPostStreamCollection):
(webkitMediaStreamSrcAddTrack):
(webkitMediaStreamSrcRemoveTrackByType):
(webkitMediaStreamSrcSetStream):
(webkitMediaStreamSrcPushVideoSample):
(webkitMediaStreamSrcPushAudioSample):
(webkitMediaStreamSrcTrackEnded):
(webkitMediaStreamSrcNew):

  • platform/mediastream/gstreamer/GStreamerMediaStreamSource.h:
Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r263832 r263836  
     12020-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
    1572020-07-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
    258
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r263658 r263836  
    5454#if ENABLE(MEDIA_STREAM)
    5555#include "GStreamerMediaStreamSource.h"
     56#include "MediaStreamPrivate.h"
    5657#endif
    5758
  • trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp

    r263457 r263836  
    11/*
    22 * Copyright (C) 2018 Metrological Group B.V.
     3 * Copyright (C) 2020 Igalia S.L.
    34 * Author: Thibault Saunier <tsaunier@igalia.com>
    45 * Author: Alejandro G. Castro <alex@igalia.com>
     6 * Author: Philippe Normand <philn@igalia.com>
    57 *
    68 * This library is free software; you can redistribute it and/or
     
    2123
    2224#include "config.h"
    23 
    24 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
    2525#include "GStreamerMediaStreamSource.h"
     26
     27#if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
    2628
    2729#include "AudioTrackPrivate.h"
     
    3032#include "GStreamerVideoCaptureSource.h"
    3133#include "MediaSampleGStreamer.h"
     34#include "MediaStreamPrivate.h"
     35#include "MediaStreamTrackPrivate.h"
    3236#include "VideoTrackPrivate.h"
    3337
    3438#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
     41using namespace WebCore;
     42
     43static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc*, GstSample*);
     44static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc*, GstSample*);
     45static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc*, MediaStreamTrackPrivate&);
     46static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc*, RealtimeMediaSource::Type);
     47
     48static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src", GST_PAD_SRC, GST_PAD_SOMETIMES,
    4749    GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8"));
    4850
    49 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src",
    50     GST_PAD_SRC,
    51     GST_PAD_SOMETIMES,
     51static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src", GST_PAD_SRC, GST_PAD_SOMETIMES,
    5252    GST_STATIC_CAPS("audio/x-raw(ANY);"));
    5353
    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);
     54GRefPtr<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);
    6965
    7066        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(),
    7669                WEBKIT_MEDIA_TRACK_TAG_HEIGHT, source.size().height(), nullptr);
    7770        }
    7871    }
    7972
    80     return taglist;
     73    GST_DEBUG("Track tags: %" GST_PTR_FORMAT, tagList.get());
     74    return tagList.leakRef();
    8175}
    8276
     
    9488    } else {
    9589        GST_FIXME("Handle %d type", static_cast<int>(track->type()));
    96 
    9790        return nullptr;
    9891    }
    9992
    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;
    10697}
    10798
     
    113104public:
    114105    virtual ~WebKitMediaStreamTrackObserver() { };
    115     WebKitMediaStreamTrackObserver(WebKitMediaStreamSrc* src)
    116         : m_mediaStreamSrc(src)
    117         , m_enabled(true) { }
     106    WebKitMediaStreamTrackObserver(GRefPtr<GstElement>&& src)
     107        : m_src(WTFMove(src)) { }
    118108    void trackStarted(MediaStreamTrackPrivate&) final { };
    119109
    120110    void trackEnded(MediaStreamTrackPrivate& track) final
    121111    {
    122         webkitMediaStreamSrcTrackEnded(m_mediaStreamSrc, track);
     112        if (m_src)
     113            webkitMediaStreamSrcTrackEnded(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), track);
    123114    }
    124115
     
    134125    void videoSampleAvailable(MediaSample& sample) final
    135126    {
    136         if (!m_enabled)
     127        if (!m_enabled || !m_src)
    137128            return;
    138129
    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);
    141132    }
    142133
    143134    void audioSamplesAvailable(const MediaTime&, const PlatformAudioData& audioData, const AudioStreamDescription&, size_t) final
    144135    {
    145         if (!m_enabled)
     136        if (!m_enabled || !m_src)
    146137            return;
    147138
    148139        auto data = static_cast<const GStreamerAudioData&>(audioData);
    149         webkitMediaStreamSrcPushAudioSample(m_mediaStreamSrc, data.getSample());
     140        webkitMediaStreamSrcPushAudioSample(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), data.getSample());
    150141    }
    151142
    152143private:
    153     WebKitMediaStreamSrc* m_mediaStreamSrc;
    154     bool m_enabled;
     144    GRefPtr<GstElement> m_src;
     145    bool m_enabled { true };
    155146};
    156147
    157 class WebKitMediaStreamObserver
    158     : public MediaStreamPrivate::Observer {
     148class WebKitMediaStreamObserver : public MediaStreamPrivate::Observer {
    159149    WTF_MAKE_FAST_ALLOCATED;
    160150public:
    161151    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    }
    166160    void activeStatusChanged() final { }
    167161
    168162    void didAddTrack(MediaStreamTrackPrivate& track) final
    169163    {
    170         webkitMediaStreamSrcAddTrack(m_mediaStreamSrc, &track, false);
     164        if (m_src)
     165            webkitMediaStreamSrcAddTrack(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), &track, false);
    171166    }
    172167
    173168    void didRemoveTrack(MediaStreamTrackPrivate& track) final
    174169    {
    175         webkitMediaStreamSrcRemoveTrackByType(m_mediaStreamSrc, track.type());
     170        if (m_src)
     171            webkitMediaStreamSrcRemoveTrackByType(WEBKIT_MEDIA_STREAM_SRC(m_src.get()), track.type());
    176172    }
    177173
    178174private:
    179     WebKitMediaStreamSrc* m_mediaStreamSrc;
     175    GRefPtr<GstElement> m_src;
    180176};
    181177
    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 
     178class InternalSource {
     179    WTF_MAKE_FAST_ALLOCATED;
     180public:
     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()));
    198202            gst_element_set_locked_state(m_src.get(), true);
    199203            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());
    203205            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
     247private:
     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
     255struct _WebKitMediaStreamSrcPrivate {
     256    CString uri;
     257    Optional<InternalSource> audioSrc;
     258    Optional<InternalSource> videoSrc;
    286259    std::unique_ptr<WebKitMediaStreamTrackObserver> mediaStreamTrackObserver;
    287260    std::unique_ptr<WebKitMediaStreamObserver> mediaStreamObserver;
    288     volatile gint npads;
    289261    RefPtr<MediaStreamPrivate> stream;
    290262    RefPtr<MediaStreamTrackPrivate> track;
    291 
    292     GstFlowCombiner* flowCombiner;
     263    GUniquePtr<GstFlowCombiner> flowCombiner;
    293264    GRefPtr<GstStreamCollection> streamCollection;
    294 };
    295 
    296 struct _WebKitMediaStreamSrcClass {
    297     GstBinClass parent_class;
    298265};
    299266
     
    304271};
    305272
    306 static GstURIType webkit_media_stream_src_uri_get_type(GType)
     273static GstURIType webkitMediaStreamSrcUriGetType(GType)
    307274{
    308275    return GST_URI_SRC;
    309276}
    310277
    311 static const gchar* const* webkit_media_stream_src_uri_get_protocols(GType)
    312 {
    313     static const gchar* protocols[] = { "mediastream", nullptr };
    314 
     278static const char* const* webkitMediaStreamSrcUriGetProtocols(GType)
     279{
     280    static const char* protocols[] = { "mediastream", nullptr };
    315281    return protocols;
    316282}
    317283
    318 static gchar* webkit_media_stream_src_uri_get_uri(GstURIHandler* handler)
     284static char* webkitMediaStreamSrcUriGetUri(GstURIHandler* handler)
    319285{
    320286    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
     290static gboolean webkitMediaStreamSrcUriSetUri(GstURIHandler* handler, const char* uri, GError**)
    328291{
    329292    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(handler);
    330     self->uri = g_strdup(uri);
    331 
     293    self->priv->uri = CString(uri);
    332294    return TRUE;
    333295}
    334296
    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;
     297static 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;
    342303    iface->set_uri = webkitMediaStreamSrcUriSetUri;
    343304}
     
    346307#define GST_CAT_DEFAULT webkitMediaStreamSrcDebug
    347308
    348 #define doInit                                                                                                                                                              \
    349     G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webkitMediaStreamSrcUriHandlerInit);                                                                                    \
    350     GST_DEBUG_CATEGORY_INIT(webkitMediaStreamSrcDebug, "webkitwebmediastreamsrc", 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); \
    352313    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); \
    353314    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);
    354315
    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
     317WEBKIT_DEFINE_TYPE_WITH_CODE(WebKitMediaStreamSrc, webkit_media_stream_src, GST_TYPE_BIN, doInit)
     318
     319static void webkitMediaStreamSrcSetProperty(GObject* object, guint propertyId, const GValue*, GParamSpec* pspec)
     320{
     321    switch (propertyId) {
    361322    default:
    362         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     323        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
    363324        break;
    364325    }
    365326}
    366327
    367 static void webkitMediaStreamSrcGetProperty(GObject* object, guint prop_id, GValue* value,
    368     GParamSpec* pspec)
    369 {
    370     switch (prop_id) {
     328static void webkitMediaStreamSrcGetProperty(GObject* object, guint propertyId, GValue* value, GParamSpec* pspec)
     329{
     330    switch (propertyId) {
    371331    case PROP_IS_LIVE:
    372332        g_value_set_boolean(value, TRUE);
    373333        break;
    374334    default:
    375         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     335        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
    376336        break;
    377337    }
    378338}
    379339
    380 static void webkitMediaStreamSrcDispose(GObject* object)
    381 {
     340static void webkitMediaStreamSrcConstructed(GObject* object)
     341{
     342    GST_CALL_PARENT(G_OBJECT_CLASS, constructed, (object));
    382343    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
     351static 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);
    386367}
    387368
     
    390371    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(object);
    391372
     373    stopObservingTracks(self);
     374
    392375    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;
    401380    }
    402381    GST_OBJECT_UNLOCK(self);
    403 
    404     g_clear_pointer(&self->uri, g_free);
    405     gst_flow_combiner_free(self->flowCombiner);
    406382}
    407383
    408384static GstStateChangeReturn webkitMediaStreamSrcChangeState(GstElement* element, GstStateChange transition)
    409385{
    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);
    431394
    432395    if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
     
    438401static void webkit_media_stream_src_class_init(WebKitMediaStreamSrcClass* klass)
    439402{
    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
     419static 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
     432static 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
     450struct 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;
    471459    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};
    512461
    513462static GstPadProbeReturn webkitMediaStreamSrcPadProbeCb(GstPad* pad, GstPadProbeInfo* info, ProbeData* data)
    514463{
    515464    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);
    518468    switch (GST_EVENT_TYPE(event)) {
    519469    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())) {
    525473            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;
    539483    }
    540484    default:
     
    545489}
    546490
    547 static gboolean webkitMediaStreamSrcSetupSrc(WebKitMediaStreamSrc* self,
    548     MediaStreamTrackPrivate* track, GstElement* element,
    549     GstStaticPadTemplate* pad_template, gboolean observe_track,
    550     bool onlyTrack)
    551 {
     491static 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
    552496    auto pad = adoptGRef(gst_element_get_static_pad(element, "src"));
    553 
    554     gst_bin_add(GST_BIN(self), element);
    555 
    556497    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
     524static 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
     541void 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);
    567550    } 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
     557static 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
     567void 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
     581static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc* self, GstSample* sample)
     582{
     583    if (self->priv->videoSrc)
     584        self->priv->videoSrc->pushSample(sample);
     585}
     586
     587static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc* self, GstSample* sample)
     588{
     589    if (self->priv->audioSrc)
     590        self->priv->audioSrc->pushSample(sample);
     591}
     592
     593static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate& track)
     594{
     595    GRefPtr<GstPad> pad;
     596
     597    GST_DEBUG_OBJECT(self, "Track %s ended", track.label().utf8().data());
    601598    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)
    679603            continue;
    680604
    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;
    684609            break;
    685610        }
     
    689614    if (!pad) {
    690615        GST_ERROR_OBJECT(self, "No pad found for %s", track.id().utf8().data());
    691 
    692616        return;
    693617    }
    694618
    695619    // Make sure that the video.videoWidth is reset to 0
    696     webkitMediaStreamSrcPostStreamCollection(self, self->stream.get());
     620    webkitMediaStreamSrcPostStreamCollection(self);
    697621    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()));
    699623    gst_pad_push_event(pad.get(), gst_event_new_eos());
    700624}
    701625
    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)
     626GstElement* 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  
    2222#pragma once
    2323
    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)
    2825
    2926#include <gst/gst.h>
     27
     28namespace WebCore {
     29class MediaStreamPrivate;
     30class MediaStreamTrackPrivate;
     31}
     32
     33G_BEGIN_DECLS
    3034
    3135#define WEBKIT_MEDIA_TRACK_TAG_WIDTH "webkit-media-stream-width"
     
    3337#define WEBKIT_MEDIA_TRACK_TAG_KIND "webkit-media-stream-kind"
    3438
    35 namespace WebCore {
    36 
    37 typedef struct _WebKitMediaStreamSrc WebKitMediaStreamSrc;
    38 
    3939#define WEBKIT_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_CAST((o), WEBKIT_TYPE_MEDIA_STREAM_SRC, WebKitMediaStreamSrc))
    4040#define WEBKIT_IS_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), WEBKIT_TYPE_MEDIA_STREAM_SRC))
    4141#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
     42GType webkit_media_stream_src_get_type(void);
    4743
    48 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC)
     44typedef struct _WebKitMediaStreamSrc WebKitMediaStreamSrc;
     45typedef struct _WebKitMediaStreamSrcClass WebKitMediaStreamSrcClass;
     46typedef struct _WebKitMediaStreamSrcPrivate WebKitMediaStreamSrcPrivate;
     47
     48struct _WebKitMediaStreamSrc {
     49    GstBin parent;
     50    WebKitMediaStreamSrcPrivate* priv;
     51};
     52
     53struct _WebKitMediaStreamSrcClass {
     54    GstBinClass parentClass;
     55};
     56
     57void webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc*, WebCore::MediaStreamPrivate*);
     58void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc*, WebCore::MediaStreamTrackPrivate*, bool onlyTrack);
     59GstElement* webkitMediaStreamSrcNew();
     60
     61G_END_DECLS
     62
     63#endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
Note: See TracChangeset for help on using the changeset viewer.