[GStreamer][WebRTC] Use LibWebRTC provided vp8 decoders and encoders
[WebKit-https.git] / Source / WebCore / platform / mediastream / libwebrtc / GStreamerVideoDecoderFactory.cpp
1 /*
2  * Copyright (C) 2018 Metrological Group B.V.
3  * Copyright (C) 2018 Igalia S.L. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * aint with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
24 #include "GStreamerVideoDecoderFactory.h"
25
26 #include "GStreamerVideoFrameLibWebRTC.h"
27 #include "webrtc/common_video/h264/h264_common.h"
28 #include "webrtc/common_video/h264/profile_level_id.h"
29 #include "webrtc/media/base/codec.h"
30 #include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
31 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
32 #include "webrtc/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.h"
33 #include "webrtc/modules/video_coding/include/video_codec_interface.h"
34 #include <gst/app/gstappsink.h>
35 #include <gst/app/gstappsrc.h>
36 #include <gst/video/video.h>
37 #include <mutex>
38 #include <wtf/Lock.h>
39 #include <wtf/StdMap.h>
40 #include <wtf/glib/RunLoopSourcePriority.h>
41 #include <wtf/text/WTFString.h>
42
43 GST_DEBUG_CATEGORY(webkit_webrtcdec_debug);
44 #define GST_CAT_DEFAULT webkit_webrtcdec_debug
45
46 namespace WebCore {
47
48 typedef struct {
49     uint64_t timestamp;
50     int64_t renderTimeMs;
51 } InputTimestamps;
52
53 class GStreamerVideoDecoder : public webrtc::VideoDecoder {
54 public:
55     GStreamerVideoDecoder()
56         : m_pictureId(0)
57         , m_firstBufferPts(GST_CLOCK_TIME_NONE)
58         , m_firstBufferDts(GST_CLOCK_TIME_NONE)
59     {
60     }
61
62     static void decodebinPadAddedCb(GstElement*,
63         GstPad* srcpad,
64         GstPad* sinkpad)
65     {
66         GST_INFO_OBJECT(srcpad, "connecting pad with %" GST_PTR_FORMAT, sinkpad);
67         if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK)
68             ASSERT_NOT_REACHED();
69     }
70
71     GstElement* pipeline()
72     {
73         return m_pipeline.get();
74     }
75
76     GstElement* makeElement(const gchar* factoryName)
77     {
78         GUniquePtr<char> name(g_strdup_printf("%s_dec_%s_%p", Name(), factoryName, this));
79
80         return gst_element_factory_make(factoryName, name.get());
81     }
82
83     int32_t InitDecode(const webrtc::VideoCodec*, int32_t) override
84     {
85         m_src = makeElement("appsrc");
86
87         auto capsfilter = CreateFilter();
88         auto decoder = makeElement("decodebin");
89
90         // Make the decoder output "parsed" frames only and let the main decodebin
91         // do the real decoding. This allows us to have optimized decoding/rendering
92         // happening in the main pipeline.
93         g_object_set(decoder, "caps", adoptGRef(gst_caps_from_string(Caps())).get(), nullptr);
94         auto sinkpad = gst_element_get_static_pad(capsfilter, "sink");
95         g_signal_connect(decoder, "pad-added", G_CALLBACK(decodebinPadAddedCb), sinkpad);
96
97         m_pipeline = makeElement("pipeline");
98         connectSimpleBusMessageCallback(m_pipeline.get());
99
100         auto sink = makeElement("appsink");
101         gst_app_sink_set_emit_signals(GST_APP_SINK(sink), true);
102         g_signal_connect(sink, "new-sample", G_CALLBACK(newSampleCallbackTramp), this);
103         // This is an encoder, everything should happen as fast as possible and not
104         // be synced on the clock.
105         g_object_set(sink, "sync", false, nullptr);
106
107         gst_bin_add_many(GST_BIN(pipeline()), m_src, decoder, capsfilter, sink, nullptr);
108         if (!gst_element_link(m_src, decoder)) {
109             GST_ERROR_OBJECT(pipeline(), "Could not link src to decoder.");
110             return WEBRTC_VIDEO_CODEC_ERROR;
111         }
112
113         if (!gst_element_link(capsfilter, sink)) {
114             GST_ERROR_OBJECT(pipeline(), "Could not link capsfilter to sink.");
115             return WEBRTC_VIDEO_CODEC_ERROR;
116         }
117
118         if (gst_element_set_state(pipeline(), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
119             GST_ERROR_OBJECT(pipeline(), "Could not set state to PLAYING.");
120             return WEBRTC_VIDEO_CODEC_ERROR;
121         }
122
123         return WEBRTC_VIDEO_CODEC_OK;
124     }
125
126     int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* callback)
127     {
128         m_imageReadyCb = callback;
129
130         return WEBRTC_VIDEO_CODEC_OK;
131     }
132
133     virtual GstElement* CreateFilter()
134     {
135         return makeElement("identity");
136     }
137
138     int32_t Release() final
139     {
140         if (m_pipeline.get()) {
141             GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
142             gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
143
144             gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
145             m_src = nullptr;
146             m_pipeline = nullptr;
147         }
148
149         return WEBRTC_VIDEO_CODEC_OK;
150     }
151
152     int32_t Decode(const webrtc::EncodedImage& inputImage,
153         bool,
154         const webrtc::CodecSpecificInfo*,
155         int64_t renderTimeMs) override
156     {
157         if (!m_src) {
158             GST_ERROR("No source set, can't decode.");
159
160             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
161         }
162
163         if (!GST_CLOCK_TIME_IS_VALID(m_firstBufferPts)) {
164             GRefPtr<GstPad> srcpad = adoptGRef(gst_element_get_static_pad(m_src, "src"));
165             m_firstBufferPts = (static_cast<guint64>(renderTimeMs)) * GST_MSECOND;
166             m_firstBufferDts = (static_cast<guint64>(inputImage.Timestamp())) * GST_MSECOND;
167         }
168
169         // FIXME- Use a GstBufferPool.
170         auto buffer = adoptGRef(gst_buffer_new_wrapped(g_memdup(inputImage._buffer, inputImage._size),
171             inputImage._size));
172         GST_BUFFER_DTS(buffer.get()) = (static_cast<guint64>(inputImage.Timestamp()) * GST_MSECOND) - m_firstBufferDts;
173         GST_BUFFER_PTS(buffer.get()) = (static_cast<guint64>(renderTimeMs) * GST_MSECOND) - m_firstBufferPts;
174         {
175             auto locker = holdLock(m_bufferMapLock);
176             InputTimestamps timestamps = {inputImage.Timestamp(), renderTimeMs};
177             m_dtsPtsMap[GST_BUFFER_PTS(buffer.get())] = timestamps;
178         }
179
180         GST_LOG_OBJECT(pipeline(), "%ld Decoding: %" GST_PTR_FORMAT, renderTimeMs, buffer.get());
181         auto sample = adoptGRef(gst_sample_new(buffer.get(), GetCapsForFrame(inputImage), nullptr, nullptr));
182         switch (gst_app_src_push_sample(GST_APP_SRC(m_src), sample.get())) {
183         case GST_FLOW_OK:
184             return WEBRTC_VIDEO_CODEC_OK;
185         case GST_FLOW_FLUSHING:
186             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
187         default:
188             return WEBRTC_VIDEO_CODEC_ERROR;
189         }
190     }
191
192     virtual GstCaps* GetCapsForFrame(const webrtc::EncodedImage& image)
193     {
194         if (!m_caps) {
195             m_caps = adoptGRef(gst_caps_new_simple(Caps(),
196                 "width", G_TYPE_INT, image._encodedWidth,
197                 "height", G_TYPE_INT, image._encodedHeight,
198                 nullptr));
199         }
200
201         return m_caps.get();
202     }
203
204     void AddDecoderIfSupported(std::vector<webrtc::SdpVideoFormat> codecList)
205     {
206         if (HasGstDecoder()) {
207             webrtc::SdpVideoFormat format = ConfigureSupportedDecoder();
208
209             codecList.push_back(format);
210         }
211     }
212
213     virtual webrtc::SdpVideoFormat ConfigureSupportedDecoder()
214     {
215         return webrtc::SdpVideoFormat(Name());
216     }
217
218     static GRefPtr<GstElementFactory> GstDecoderFactory(const char *capsStr)
219     {
220         auto all_decoders = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER,
221             GST_RANK_MARGINAL);
222         auto caps = adoptGRef(gst_caps_from_string(capsStr));
223         auto decoders = gst_element_factory_list_filter(all_decoders,
224             caps.get(), GST_PAD_SINK, FALSE);
225
226         gst_plugin_feature_list_free(all_decoders);
227         GRefPtr<GstElementFactory> res;
228         if (decoders)
229             res = GST_ELEMENT_FACTORY(decoders->data);
230         gst_plugin_feature_list_free(decoders);
231
232         return res;
233     }
234
235     bool HasGstDecoder()
236     {
237         return GstDecoderFactory(Caps());
238     }
239
240     GstFlowReturn newSampleCallback(GstElement* sink)
241     {
242         auto sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
243         auto buffer = gst_sample_get_buffer(sample);
244
245         m_bufferMapLock.lock();
246         // Make sure that the frame.timestamp == previsouly input_frame._timeStamp
247         // as it is required by the VideoDecoder baseclass.
248         auto timestamps = m_dtsPtsMap[GST_BUFFER_PTS(buffer)];
249         m_dtsPtsMap.erase(GST_BUFFER_PTS(buffer));
250         m_bufferMapLock.unlock();
251
252         auto frame(LibWebRTCVideoFrameFromGStreamerSample(sample, webrtc::kVideoRotation_0,
253             timestamps.timestamp, timestamps.renderTimeMs));
254
255         GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE;
256         GST_LOG_OBJECT(pipeline(), "Output decoded frame! %d -> %" GST_PTR_FORMAT,
257             frame->timestamp(), buffer);
258
259         m_imageReadyCb->Decoded(*frame.get(), absl::optional<int32_t>(), absl::optional<uint8_t>());
260
261         return GST_FLOW_OK;
262     }
263
264     virtual const gchar* Caps() = 0;
265     virtual webrtc::VideoCodecType CodecType() = 0;
266     const char* ImplementationName() const { return "GStreamer"; }
267     virtual const gchar* Name() = 0;
268
269 protected:
270     GRefPtr<GstCaps> m_caps;
271     gint m_pictureId;
272
273 private:
274     static GstFlowReturn newSampleCallbackTramp(GstElement* sink, GStreamerVideoDecoder* enc)
275     {
276         return enc->newSampleCallback(sink);
277     }
278
279     GRefPtr<GstElement> m_pipeline;
280     GstElement* m_src;
281
282     GstVideoInfo m_info;
283     webrtc::DecodedImageCallback* m_imageReadyCb;
284
285     Lock m_bufferMapLock;
286     StdMap<GstClockTime, InputTimestamps> m_dtsPtsMap;
287     GstClockTime m_firstBufferPts;
288     GstClockTime m_firstBufferDts;
289 };
290
291 class H264Decoder : public GStreamerVideoDecoder {
292 public:
293     H264Decoder() { }
294
295     int32_t InitDecode(const webrtc::VideoCodec* codecInfo, int32_t nCores) final
296     {
297         if (codecInfo && codecInfo->codecType != webrtc::kVideoCodecH264)
298             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
299
300         m_profile = nullptr;
301         if (codecInfo) {
302             auto h264Info = codecInfo->H264();
303
304             switch (h264Info.profile) {
305             case webrtc::H264::kProfileConstrainedBaseline:
306                 m_profile = "constrained-baseline";
307                 break;
308             case webrtc::H264::kProfileBaseline:
309                 m_profile = "baseline";
310                 break;
311             case webrtc::H264::kProfileMain:
312                 m_profile = "main";
313                 break;
314             case webrtc::H264::kProfileConstrainedHigh:
315                 m_profile = "constrained-high";
316                 break;
317             case webrtc::H264::kProfileHigh:
318                 m_profile = "high";
319                 break;
320             }
321         }
322
323         return GStreamerVideoDecoder::InitDecode(codecInfo, nCores);
324     }
325
326     GstCaps* GetCapsForFrame(const webrtc::EncodedImage& image) final
327     {
328         if (!m_caps) {
329             m_caps = adoptGRef(gst_caps_new_simple(Caps(),
330                 "width", G_TYPE_INT, image._encodedWidth,
331                 "height", G_TYPE_INT, image._encodedHeight,
332                 "profile", G_TYPE_STRING, m_profile ? m_profile : "baseline",
333                 "stream-format", G_TYPE_STRING, "byte-stream",
334                 "alignment", G_TYPE_STRING, "au",
335                 nullptr));
336         }
337
338         return m_caps.get();
339     }
340     const gchar* Caps() final { return "video/x-h264"; }
341     const gchar* Name() final { return cricket::kH264CodecName; }
342     webrtc::VideoCodecType CodecType() final { return webrtc::kVideoCodecH264; }
343
344 private:
345     const gchar* m_profile;
346 };
347
348 class VP8Decoder : public GStreamerVideoDecoder {
349 public:
350     VP8Decoder() { }
351     const gchar* Caps() final { return "video/x-vp8"; }
352     const gchar* Name() final { return cricket::kVp8CodecName; }
353     webrtc::VideoCodecType CodecType() final { return webrtc::kVideoCodecVP8; }
354     static std::unique_ptr<webrtc::VideoDecoder> Create()
355     {
356         auto factory = GstDecoderFactory("video/x-vp8");
357
358         if (factory && !g_strcmp0(GST_OBJECT_NAME(GST_OBJECT(factory.get())), "vp8dec")) {
359             GST_INFO("Our best GStreamer VP8 decoder is vp8dec, better use the one from LibWebRTC");
360
361             return std::unique_ptr<webrtc::VideoDecoder>(new webrtc::LibvpxVp8Decoder());
362         }
363
364         return std::unique_ptr<webrtc::VideoDecoder>(new VP8Decoder());
365     }
366 };
367
368 std::unique_ptr<webrtc::VideoDecoder> GStreamerVideoDecoderFactory::CreateVideoDecoder(const webrtc::SdpVideoFormat& format)
369 {
370     webrtc::VideoDecoder* dec;
371
372     if (format.name == cricket::kH264CodecName)
373         dec = new H264Decoder();
374     else if (format.name == cricket::kVp8CodecName)
375         return VP8Decoder::Create();
376     else {
377         GST_ERROR("Could not create decoder for %s", format.name.c_str());
378
379         return nullptr;
380     }
381
382     return std::unique_ptr<webrtc::VideoDecoder>(dec);
383 }
384
385 GStreamerVideoDecoderFactory::GStreamerVideoDecoderFactory()
386 {
387     static std::once_flag debugRegisteredFlag;
388
389     std::call_once(debugRegisteredFlag, [] {
390         GST_DEBUG_CATEGORY_INIT(webkit_webrtcdec_debug, "webkitlibwebrtcvideodecoder", 0, "WebKit WebRTC video decoder");
391     });
392 }
393 std::vector<webrtc::SdpVideoFormat> GStreamerVideoDecoderFactory::GetSupportedFormats() const
394 {
395     std::vector<webrtc::SdpVideoFormat> formats;
396
397     VP8Decoder().AddDecoderIfSupported(formats);
398     H264Decoder().AddDecoderIfSupported(formats);
399
400     return formats;
401 }
402 }
403 #endif