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 "MockGStreamerVideoCaptureSource.h"
26
27#include "MediaSampleGStreamer.h"
28#include "MockRealtimeVideoSource.h"
29
30#include <gst/app/gstappsrc.h>
31
32namespace WebCore {
33
34class WrappedMockRealtimeVideoSource : public MockRealtimeVideoSource {
35public:
36 WrappedMockRealtimeVideoSource(String&& deviceID, String&& name, String&& hashSalt)
37 : MockRealtimeVideoSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
38 {
39 }
40
41 void updateSampleBuffer()
42 {
43 auto imageBuffer = this->imageBuffer();
44 if (!imageBuffer)
45 return;
46
47 int fpsNumerator, fpsDenominator;
48 gst_util_double_to_fraction(frameRate(), &fpsNumerator, &fpsDenominator);
49 auto imageSize = imageBuffer->internalSize();
50 auto caps = adoptGRef(gst_caps_new_simple("video/x-raw",
51 "format", G_TYPE_STRING, "BGRA",
52 "width", G_TYPE_INT, imageSize.width(),
53 "height", G_TYPE_INT, imageSize.height(),
54 "framerate", GST_TYPE_FRACTION, fpsNumerator, fpsDenominator, nullptr));
55 auto data = imageBuffer->toBGRAData();
56 auto size = data.size();
57 auto buffer = adoptGRef(gst_buffer_new_wrapped(g_memdup(data.releaseBuffer().get(), size), size));
58 auto gstSample = adoptGRef(gst_sample_new(buffer.get(), caps.get(), nullptr, nullptr));
59
60 videoSampleAvailable(MediaSampleGStreamer::create(WTFMove(gstSample), FloatSize(), String()));
61 }
62};
63
64CaptureSourceOrError MockRealtimeVideoSource::create(String&& deviceID,
65 String&& name, String&& hashSalt, const MediaConstraints* constraints)
66{
67 auto source = adoptRef(*new MockGStreamerVideoCaptureSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)));
68
69 if (constraints && source->applyConstraints(*constraints))
70 return { };
71
72 return CaptureSourceOrError(WTFMove(source));
73}
74
75void MockGStreamerVideoCaptureSource::startProducingData()
76{
77 GStreamerVideoCaptureSource::startProducingData();
78 m_wrappedSource->start();
79}
80
81void MockGStreamerVideoCaptureSource::stopProducingData()
82{
83 m_wrappedSource->stop();
84
85 GStreamerVideoCaptureSource::stopProducingData();
86}
87
88void MockGStreamerVideoCaptureSource::videoSampleAvailable(MediaSample& sample)
89{
90 auto src = capturer()->source();
91
92 if (src) {
93 auto gstsample = static_cast<MediaSampleGStreamer*>(&sample)->platformSample().sample.gstSample;
94 gst_app_src_push_sample(GST_APP_SRC(src), gstsample);
95 }
96}
97
98MockGStreamerVideoCaptureSource::MockGStreamerVideoCaptureSource(String&& deviceID, String&& name, String&& hashSalt)
99 : GStreamerVideoCaptureSource(String { deviceID }, String { name }, String { hashSalt }, "appsrc")
100 , m_wrappedSource(std::make_unique<WrappedMockRealtimeVideoSource>(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)))
101{
102 m_wrappedSource->addObserver(*this);
103}
104
105MockGStreamerVideoCaptureSource::~MockGStreamerVideoCaptureSource()
106{
107 m_wrappedSource->removeObserver(*this);
108}
109
110Optional<RealtimeMediaSource::ApplyConstraintsError> MockGStreamerVideoCaptureSource::applyConstraints(const MediaConstraints& constraints)
111{
112 m_wrappedSource->applyConstraints(constraints);
113 return GStreamerVideoCaptureSource::applyConstraints(constraints);
114}
115
116void MockGStreamerVideoCaptureSource::applyConstraints(const MediaConstraints& constraints, ApplyConstraintsHandler&& completionHandler)
117{
118 m_wrappedSource->applyConstraints(constraints, WTFMove(completionHandler));
119}
120
121const RealtimeMediaSourceSettings& MockGStreamerVideoCaptureSource::settings()
122{
123 return m_wrappedSource->settings();
124}
125
126const RealtimeMediaSourceCapabilities& MockGStreamerVideoCaptureSource::capabilities()
127{
128 m_capabilities = m_wrappedSource->capabilities();
129 m_currentSettings = m_wrappedSource->settings();
130 return m_capabilities.value();
131}
132
133void MockGStreamerVideoCaptureSource::captureFailed()
134{
135 stop();
136
137 RealtimeMediaSource::captureFailed();
138}
139
140} // namespace WebCore
141
142#endif // ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
143