Unreviewed, rolling out r234489.
[WebKit-https.git] / Source / WebCore / platform / mediastream / gstreamer / GStreamerVideoCaptureSource.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(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
25 #include "GStreamerVideoCaptureSource.h"
26
27 #include "GStreamerCaptureDeviceManager.h"
28 #include "MediaSampleGStreamer.h"
29
30 #include <gst/app/gstappsink.h>
31 #include <webrtc/api/mediastreaminterface.h>
32 #include <webrtc/api/peerconnectioninterface.h>
33 #include <webrtc/media/base/videocommon.h>
34 #include <webrtc/media/engine/webrtcvideocapturer.h>
35 #include <webrtc/media/engine/webrtcvideocapturerfactory.h>
36 #include <webrtc/modules/video_capture/video_capture_defines.h>
37
38 namespace WebCore {
39
40 const static int defaultWidth = 640;
41 const static int defaultHeight = 480;
42
43 GST_DEBUG_CATEGORY(webkit_video_capture_source_debug);
44 #define GST_CAT_DEFAULT webkit_video_capture_source_debug
45
46 static void initializeGStreamerDebug()
47 {
48     static std::once_flag debugRegisteredFlag;
49     std::call_once(debugRegisteredFlag, [] {
50         GST_DEBUG_CATEGORY_INIT(webkit_video_capture_source_debug, "webkitvideocapturesource", 0,
51             "WebKit Video Capture Source.");
52     });
53 }
54
55 class GStreamerVideoCaptureSourceFactory final : public RealtimeMediaSource::VideoCaptureFactory {
56 public:
57     CaptureSourceOrError createVideoCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
58     {
59         return GStreamerVideoCaptureSource::create(device.persistentId(), constraints);
60     }
61 };
62
63 RealtimeMediaSource::VideoCaptureFactory& libWebRTCVideoCaptureSourceFactory()
64 {
65     static NeverDestroyed<GStreamerVideoCaptureSourceFactory> factory;
66     return factory.get();
67 }
68
69 CaptureSourceOrError GStreamerVideoCaptureSource::create(const String& deviceID, const MediaConstraints* constraints)
70 {
71     auto device = GStreamerVideoCaptureDeviceManager::singleton().gstreamerDeviceWithUID(deviceID);
72     if (!device) {
73         auto errorMessage = String::format("GStreamerVideoCaptureSource::create(): GStreamer did not find the device: %s.", deviceID.utf8().data());
74         return CaptureSourceOrError(WTFMove(errorMessage));
75     }
76
77     auto source = adoptRef(*new GStreamerVideoCaptureSource(device.value()));
78
79     if (constraints) {
80         auto result = source->applyConstraints(*constraints);
81         if (result)
82             return WTFMove(result.value().first);
83     }
84     return CaptureSourceOrError(WTFMove(source));
85 }
86
87 RealtimeMediaSource::VideoCaptureFactory& GStreamerVideoCaptureSource::factory()
88 {
89     return libWebRTCVideoCaptureSourceFactory();
90 }
91
92 GStreamerVideoCaptureSource::GStreamerVideoCaptureSource(const String& deviceID, const String& name, const gchar *source_factory)
93     : RealtimeMediaSource(deviceID, RealtimeMediaSource::Type::Video, name)
94     , m_capturer(std::make_unique<GStreamerVideoCapturer>(source_factory))
95 {
96     initializeGStreamerDebug();
97 }
98
99 GStreamerVideoCaptureSource::GStreamerVideoCaptureSource(GStreamerCaptureDevice device)
100     : RealtimeMediaSource(device.persistentId(), RealtimeMediaSource::Type::Video, device.label())
101     , m_capturer(std::make_unique<GStreamerVideoCapturer>(device))
102 {
103     initializeGStreamerDebug();
104 }
105
106 GStreamerVideoCaptureSource::~GStreamerVideoCaptureSource()
107 {
108 }
109
110 bool GStreamerVideoCaptureSource::applySize(const IntSize &size)
111 {
112     m_capturer->setSize(size.width(), size.height());
113
114     return true;
115 }
116
117 bool GStreamerVideoCaptureSource::applyFrameRate(double framerate)
118 {
119     m_capturer->setFrameRate(framerate);
120
121     return true;
122 }
123
124 void GStreamerVideoCaptureSource::startProducingData()
125 {
126     m_capturer->setupPipeline();
127     m_capturer->setSize(size().width(), size().height());
128     m_capturer->setFrameRate(frameRate());
129     g_signal_connect(m_capturer->sink(), "new-sample", G_CALLBACK(newSampleCallback), this);
130     m_capturer->play();
131 }
132
133 GstFlowReturn GStreamerVideoCaptureSource::newSampleCallback(GstElement* sink, GStreamerVideoCaptureSource* source)
134 {
135     auto gstSample = adoptGRef(gst_app_sink_pull_sample(GST_APP_SINK(sink)));
136     auto mediaSample = MediaSampleGStreamer::create(WTFMove(gstSample), WebCore::FloatSize(), String());
137
138     // FIXME - Check how presentationSize is supposed to be used here.
139     callOnMainThread([protectedThis = makeRef(*source), mediaSample = WTFMove(mediaSample)] {
140         protectedThis->videoSampleAvailable(mediaSample.get());
141     });
142
143     return GST_FLOW_OK;
144 }
145
146 void GStreamerVideoCaptureSource::stopProducingData()
147 {
148     g_signal_handlers_disconnect_by_func(m_capturer->sink(), reinterpret_cast<gpointer>(newSampleCallback), this);
149     m_capturer->stop();
150
151     GST_INFO("Reset height and width after stopping source");
152     setHeight(0);
153     setWidth(0);
154 }
155
156 const RealtimeMediaSourceCapabilities& GStreamerVideoCaptureSource::capabilities() const
157 {
158     if (m_capabilities)
159         return m_capabilities.value();
160
161     RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
162     GRefPtr<GstCaps> caps = adoptGRef(m_capturer->caps());
163     int32_t minWidth = G_MAXINT32, maxWidth = 0, minHeight = G_MAXINT32, maxHeight = 0;
164     double minFramerate = G_MAXDOUBLE, maxFramerate = G_MINDOUBLE;
165
166     for (guint i = 0; i < gst_caps_get_size(caps.get()); i++) {
167         GstStructure* str = gst_caps_get_structure(caps.get(), i);
168
169         // Only accept raw video for now.
170         if (!gst_structure_has_name(str, "video/x-raw"))
171             continue;
172
173         int32_t tmpMinWidth, tmpMinHeight, tmpMinFPSNumerator, tmpMinFPSDenominator;
174         int32_t tmpMaxWidth, tmpMaxHeight, tmpMaxFPSNumerator, tmpMaxFPSDenominator;
175         double tmpMinFramerate = G_MAXDOUBLE, tmpMaxFramerate = G_MINDOUBLE;
176
177         if (!gst_structure_get(str, "width", GST_TYPE_INT_RANGE, &tmpMinWidth, &tmpMaxWidth, "height", GST_TYPE_INT_RANGE, &tmpMinHeight, &tmpMaxHeight, nullptr)) {
178             if (!gst_structure_get(str, "width", G_TYPE_INT, &tmpMinWidth, "height", G_TYPE_INT, &tmpMinHeight, nullptr))
179                 continue;
180
181             tmpMaxWidth = tmpMinWidth;
182             tmpMaxHeight = tmpMinHeight;
183         }
184
185         if (gst_structure_get(str, "framerate", GST_TYPE_FRACTION_RANGE, &tmpMinFPSNumerator, &tmpMinFPSDenominator, &tmpMaxFPSNumerator, &tmpMaxFPSDenominator, nullptr)) {
186             gst_util_fraction_to_double(tmpMinFPSNumerator, tmpMinFPSDenominator, &tmpMinFramerate);
187             gst_util_fraction_to_double(tmpMaxFPSNumerator, tmpMaxFPSDenominator, &tmpMaxFramerate);
188         } else if (gst_structure_get(str,
189             "framerate", GST_TYPE_FRACTION, &tmpMinFPSNumerator, &tmpMinFPSDenominator, nullptr)) {
190             tmpMaxFPSNumerator = tmpMinFPSNumerator;
191             tmpMaxFPSDenominator = tmpMinFPSDenominator;
192             gst_util_fraction_to_double(tmpMinFPSNumerator, tmpMinFPSDenominator, &tmpMinFramerate);
193             gst_util_fraction_to_double(tmpMaxFPSNumerator, tmpMaxFPSDenominator, &tmpMaxFramerate);
194         } else {
195             const GValue* frameRates(gst_structure_get_value(str, "framerate"));
196             tmpMinFramerate = G_MAXDOUBLE;
197             tmpMaxFramerate = 0.0;
198
199             guint frameRatesLength = static_cast<guint>(gst_value_list_get_size(frameRates)) - 1;
200
201             for (guint i = 0; i < frameRatesLength; i++) {
202                 double tmpFrameRate;
203                 const GValue* val = gst_value_list_get_value(frameRates, i);
204
205                 ASSERT(G_VALUE_TYPE(val) == GST_TYPE_FRACTION);
206                 gst_util_fraction_to_double(gst_value_get_fraction_numerator(val),
207                     gst_value_get_fraction_denominator(val), &tmpFrameRate);
208
209                 tmpMinFramerate = std::min(tmpMinFramerate, tmpFrameRate);
210                 tmpMaxFramerate = std::max(tmpMaxFramerate, tmpFrameRate);
211             }
212
213             if (i > 0) {
214                 minWidth = std::min(tmpMinWidth, minWidth);
215                 minHeight = std::min(tmpMinHeight, minHeight);
216                 minFramerate = std::min(tmpMinFramerate, minFramerate);
217
218                 maxWidth = std::max(tmpMaxWidth, maxWidth);
219                 maxHeight = std::max(tmpMaxHeight, maxHeight);
220                 maxFramerate = std::max(tmpMaxFramerate, maxFramerate);
221             } else {
222                 minWidth = tmpMinWidth;
223                 minHeight = tmpMinHeight;
224                 minFramerate = tmpMinFramerate;
225
226                 maxWidth = tmpMaxWidth;
227                 maxHeight = tmpMaxHeight;
228                 maxFramerate = tmpMaxFramerate;
229             }
230         }
231
232         capabilities.setDeviceId(id());
233         capabilities.setWidth(CapabilityValueOrRange(minWidth, maxWidth));
234         capabilities.setHeight(CapabilityValueOrRange(minHeight, maxHeight));
235         capabilities.setFrameRate(CapabilityValueOrRange(minFramerate, maxFramerate));
236         m_capabilities = WTFMove(capabilities);
237     }
238
239     return m_capabilities.value();
240 }
241
242 const RealtimeMediaSourceSettings& GStreamerVideoCaptureSource::settings() const
243 {
244     if (!m_currentSettings) {
245         RealtimeMediaSourceSettings settings;
246         settings.setDeviceId(id());
247
248         RealtimeMediaSourceSupportedConstraints supportedConstraints;
249         supportedConstraints.setSupportsDeviceId(true);
250         supportedConstraints.setSupportsFacingMode(true);
251         supportedConstraints.setSupportsWidth(true);
252         supportedConstraints.setSupportsHeight(true);
253         supportedConstraints.setSupportsAspectRatio(true);
254         supportedConstraints.setSupportsFrameRate(true);
255         settings.setSupportedConstraints(supportedConstraints);
256
257         m_currentSettings = WTFMove(settings);
258     }
259
260     m_currentSettings->setWidth(size().width());
261     m_currentSettings->setHeight(size().height());
262     m_currentSettings->setFrameRate(frameRate());
263     m_currentSettings->setAspectRatio(aspectRatio());
264     m_currentSettings->setFacingMode(facingMode());
265     return m_currentSettings.value();
266 }
267
268 } // namespace WebCore
269
270 #endif // ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC)