[WPE][GTK] Bump minimum versions of GLib, GTK, libsoup, ATK, GStreamer, and Cairo
[WebKit-https.git] / Source / WebCore / platform / mediastream / gstreamer / GStreamerCapturer.cpp
1 /*
2  * Copyright (C) 2018 Metrological Group B.V.
3  * Author: Thibault Saunier <tsaunier@igalia.com>
4  * Author: Alejandro G. Castro <alex@igalia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * aint with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
25 #include "GStreamerCapturer.h"
26
27 #include <gst/app/gstappsink.h>
28 #include <gst/app/gstappsrc.h>
29 #include <mutex>
30 #include <webrtc/api/mediastreaminterface.h>
31
32 GST_DEBUG_CATEGORY(webkit_capturer_debug);
33 #define GST_CAT_DEFAULT webkit_capturer_debug
34
35 namespace WebCore {
36
37 static void initializeGStreamerAndDebug()
38 {
39     initializeGStreamer();
40
41     static std::once_flag debugRegisteredFlag;
42     std::call_once(debugRegisteredFlag, [] {
43         GST_DEBUG_CATEGORY_INIT(webkit_capturer_debug, "webkitcapturer", 0, "WebKit Capturer");
44     });
45 }
46
47 GStreamerCapturer::GStreamerCapturer(GStreamerCaptureDevice device, GRefPtr<GstCaps> caps)
48     : m_device(device.device())
49     , m_caps(caps)
50     , m_sourceFactory(nullptr)
51 {
52     initializeGStreamerAndDebug();
53 }
54
55 GStreamerCapturer::GStreamerCapturer(const char* sourceFactory, GRefPtr<GstCaps> caps)
56     : m_device(nullptr)
57     , m_caps(caps)
58     , m_sourceFactory(sourceFactory)
59 {
60     initializeGStreamerAndDebug();
61 }
62
63 GStreamerCapturer::~GStreamerCapturer()
64 {
65     if (m_pipeline)
66         disconnectSimpleBusMessageCallback(pipeline());
67 }
68
69 GstElement* GStreamerCapturer::createSource()
70 {
71     if (m_sourceFactory) {
72         m_src = makeElement(m_sourceFactory);
73         if (GST_IS_APP_SRC(m_src.get()))
74             g_object_set(m_src.get(), "is-live", true, "format", GST_FORMAT_TIME, nullptr);
75
76         ASSERT(m_src);
77         return m_src.get();
78     }
79
80     ASSERT(m_device);
81     GUniquePtr<char> sourceName(g_strdup_printf("%s_%p", name(), this));
82     m_src = gst_device_create_element(m_device.get(), sourceName.get());
83     ASSERT(m_src);
84
85     return m_src.get();
86 }
87
88 GstCaps* GStreamerCapturer::caps()
89 {
90     if (m_sourceFactory) {
91         GRefPtr<GstElement> element = makeElement(m_sourceFactory);
92         auto pad = adoptGRef(gst_element_get_static_pad(element.get(), "src"));
93
94         return gst_pad_query_caps(pad.get(), nullptr);
95     }
96
97     ASSERT(m_device);
98     return gst_device_get_caps(m_device.get());
99 }
100
101 void GStreamerCapturer::setupPipeline()
102 {
103     if (m_pipeline)
104         disconnectSimpleBusMessageCallback(pipeline());
105
106     m_pipeline = makeElement("pipeline");
107
108     GRefPtr<GstElement> source = createSource();
109     GRefPtr<GstElement> converter = createConverter();
110
111     m_capsfilter = makeElement("capsfilter");
112     m_tee = makeElement("tee");
113     m_sink = makeElement("appsink");
114
115     gst_app_sink_set_emit_signals(GST_APP_SINK(m_sink.get()), TRUE);
116     g_object_set(m_capsfilter.get(), "caps", m_caps.get(), nullptr);
117
118     gst_bin_add_many(GST_BIN(m_pipeline.get()), source.get(), converter.get(), m_capsfilter.get(), m_tee.get(), nullptr);
119     gst_element_link_many(source.get(), converter.get(), m_capsfilter.get(), m_tee.get(), nullptr);
120
121     addSink(m_sink.get());
122
123     connectSimpleBusMessageCallback(pipeline());
124 }
125
126 GstElement* GStreamerCapturer::makeElement(const char* factoryName)
127 {
128     auto element = gst_element_factory_make(factoryName, nullptr);
129     ASSERT(element);
130     GUniquePtr<char> capturerName(g_strdup_printf("%s_capturer_%s_%p", name(), GST_OBJECT_NAME(element), this));
131     gst_object_set_name(GST_OBJECT(element), capturerName.get());
132
133     return element;
134 }
135
136 void GStreamerCapturer::addSink(GstElement* newSink)
137 {
138     ASSERT(m_pipeline);
139     ASSERT(m_tee);
140
141     auto queue = makeElement("queue");
142     gst_bin_add_many(GST_BIN(pipeline()), queue, newSink, nullptr);
143     gst_element_sync_state_with_parent(queue);
144     gst_element_sync_state_with_parent(newSink);
145
146     if (!gst_element_link_pads(m_tee.get(), "src_%u", queue, "sink")) {
147         ASSERT_NOT_REACHED();
148         return;
149     }
150
151     if (!gst_element_link(queue, newSink)) {
152         ASSERT_NOT_REACHED();
153         return;
154     }
155
156     GST_INFO_OBJECT(pipeline(), "Adding sink: %" GST_PTR_FORMAT, newSink);
157
158     GUniquePtr<char> dumpName(g_strdup_printf("%s_sink_%s_added", GST_OBJECT_NAME(pipeline()), GST_OBJECT_NAME(newSink)));
159     GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(pipeline()), GST_DEBUG_GRAPH_SHOW_ALL, dumpName.get());
160 }
161
162 void GStreamerCapturer::play()
163 {
164     ASSERT(m_pipeline);
165
166     GST_INFO_OBJECT(pipeline(), "Going to PLAYING!");
167
168     gst_element_set_state(pipeline(), GST_STATE_PLAYING);
169 }
170
171 void GStreamerCapturer::stop()
172 {
173     ASSERT(m_pipeline);
174
175     GST_INFO_OBJECT(pipeline(), "Tearing down!");
176
177     // Make sure to remove sync handler before tearing down, avoiding
178     // possible deadlocks.
179     GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(pipeline())));
180     gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
181
182     gst_element_set_state(pipeline(), GST_STATE_NULL);
183 }
184
185 } // namespace WebCore
186
187 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)