43427a8ffa87ac09df708621e1aef7127bfbff50
[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/include/video_codec_interface.h"
33 #include <gst/app/gstappsink.h>
34 #include <gst/app/gstappsrc.h>
35 #include <gst/video/video.h>
36 #include <mutex>
37 #include <wtf/Lock.h>
38 #include <wtf/StdMap.h>
39 #include <wtf/glib/RunLoopSourcePriority.h>
40 #include <wtf/text/WTFString.h>
41
42 GST_DEBUG_CATEGORY(webkit_webrtcdec_debug);
43 #define GST_CAT_DEFAULT webkit_webrtcdec_debug
44
45 namespace WebCore {
46
47 class GStreamerVideoDecoder : public webrtc::VideoDecoder {
48 public:
49     GStreamerVideoDecoder()
50         : m_pictureId(0)
51         , m_firstBufferPts(GST_CLOCK_TIME_NONE)
52         , m_firstBufferDts(GST_CLOCK_TIME_NONE)
53     {
54     }
55
56     static void decodebinPadAddedCb(GstElement*,
57         GstPad* srcpad,
58         GstPad* sinkpad)
59     {
60         GST_INFO_OBJECT(srcpad, "connecting pad with %" GST_PTR_FORMAT, sinkpad);
61         if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK)
62             ASSERT_NOT_REACHED();
63     }
64
65     GstElement* pipeline()
66     {
67         return m_pipeline.get();
68     }
69
70     GstElement* makeElement(const gchar* factoryName)
71     {
72         GUniquePtr<char> name(g_strdup_printf("%s_dec_%s_%p", Name(), factoryName, this));
73
74         return gst_element_factory_make(factoryName, name.get());
75     }
76
77     int32_t InitDecode(const webrtc::VideoCodec*, int32_t)
78     {
79         m_src = makeElement("appsrc");
80
81         auto capsfilter = CreateFilter();
82         auto decoder = makeElement("decodebin");
83
84         // Make the decoder output "parsed" frames only and let the main decodebin
85         // do the real decoding. This allows us to have optimized decoding/rendering
86         // happening in the main pipeline.
87         g_object_set(decoder, "caps", adoptGRef(gst_caps_from_string(Caps())).get(), nullptr);
88         auto sinkpad = gst_element_get_static_pad(capsfilter, "sink");
89         g_signal_connect(decoder, "pad-added", G_CALLBACK(decodebinPadAddedCb), sinkpad);
90
91         m_pipeline = makeElement("pipeline");
92         connectSimpleBusMessageCallback(m_pipeline.get());
93
94         auto sink = makeElement("appsink");
95         gst_app_sink_set_emit_signals(GST_APP_SINK(sink), true);
96         g_signal_connect(sink, "new-sample", G_CALLBACK(newSampleCallbackTramp), this);
97         // This is an encoder, everything should happen as fast as possible and not
98         // be synced on the clock.
99         g_object_set(sink, "sync", false, nullptr);
100
101         gst_bin_add_many(GST_BIN(pipeline()), m_src, decoder, capsfilter, sink, nullptr);
102         if (!gst_element_link(m_src, decoder)) {
103             GST_ERROR_OBJECT(pipeline(), "Could not link src to decoder.");
104             return WEBRTC_VIDEO_CODEC_ERROR;
105         }
106
107         if (!gst_element_link(capsfilter, sink)) {
108             GST_ERROR_OBJECT(pipeline(), "Could not link capsfilter to sink.");
109             return WEBRTC_VIDEO_CODEC_ERROR;
110         }
111
112         if (gst_element_set_state(pipeline(), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
113             GST_ERROR_OBJECT(pipeline(), "Could not set state to PLAYING.");
114             return WEBRTC_VIDEO_CODEC_ERROR;
115         }
116
117         return WEBRTC_VIDEO_CODEC_OK;
118     }
119
120     int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* callback)
121     {
122         m_imageReadyCb = callback;
123
124         return WEBRTC_VIDEO_CODEC_OK;
125     }
126
127     virtual GstElement* CreateFilter()
128     {
129         return makeElement("identity");
130     }
131
132     int32_t Release() final
133     {
134         if (m_pipeline.get()) {
135             GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
136             gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
137
138             gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
139             m_src = nullptr;
140             m_pipeline = nullptr;
141         }
142
143         return WEBRTC_VIDEO_CODEC_OK;
144     }
145
146     int32_t Decode(const webrtc::EncodedImage& inputImage,
147         bool,
148         const webrtc::CodecSpecificInfo*,
149         int64_t renderTimeMs) override
150     {
151         if (!m_src) {
152             GST_ERROR("No source set, can't decode.");
153
154             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
155         }
156
157         if (!GST_CLOCK_TIME_IS_VALID(m_firstBufferPts)) {
158             GRefPtr<GstPad> srcpad = adoptGRef(gst_element_get_static_pad(m_src, "src"));
159             m_firstBufferPts = (static_cast<guint64>(renderTimeMs)) * GST_MSECOND;
160             m_firstBufferDts = (static_cast<guint64>(inputImage.Timestamp())) * GST_MSECOND;
161         }
162
163         // FIXME- Use a GstBufferPool.
164         auto buffer = adoptGRef(gst_buffer_new_wrapped(g_memdup(inputImage._buffer, inputImage._size),
165             inputImage._size));
166         GST_BUFFER_DTS(buffer.get()) = (static_cast<guint64>(inputImage.Timestamp()) * GST_MSECOND) - m_firstBufferDts;
167         GST_BUFFER_PTS(buffer.get()) = (static_cast<guint64>(renderTimeMs) * GST_MSECOND) - m_firstBufferPts;
168         {
169             auto locker = holdLock(m_bufferMapLock);
170             m_dtsPtsMap[GST_BUFFER_PTS(buffer.get())] = inputImage.Timestamp();
171         }
172
173         GST_LOG_OBJECT(pipeline(), "%ld Decoding: %" GST_PTR_FORMAT, renderTimeMs, buffer.get());
174         auto sample = adoptGRef(gst_sample_new(buffer.get(), GetCapsForFrame(inputImage), nullptr, nullptr));
175         switch (gst_app_src_push_sample(GST_APP_SRC(m_src), sample.get())) {
176         case GST_FLOW_OK:
177             return WEBRTC_VIDEO_CODEC_OK;
178         case GST_FLOW_FLUSHING:
179             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
180         default:
181             return WEBRTC_VIDEO_CODEC_ERROR;
182         }
183     }
184
185     GstCaps* GetCapsForFrame(const webrtc::EncodedImage& image)
186     {
187         if (!m_caps) {
188             m_caps = adoptGRef(gst_caps_new_simple(Caps(),
189                 "width", G_TYPE_INT, image._encodedWidth,
190                 "height", G_TYPE_INT, image._encodedHeight,
191                 nullptr));
192         }
193
194         return m_caps.get();
195     }
196
197     void AddDecoderIfSupported(std::vector<webrtc::SdpVideoFormat> codecList)
198     {
199         if (HasGstDecoder()) {
200             webrtc::SdpVideoFormat format = ConfigureSupportedDecoder();
201
202             codecList.push_back(format);
203         }
204     }
205
206     virtual webrtc::SdpVideoFormat ConfigureSupportedDecoder()
207     {
208         return webrtc::SdpVideoFormat(Name());
209     }
210
211     bool HasGstDecoder()
212     {
213
214         auto all_decoders = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER,
215             GST_RANK_MARGINAL);
216         auto caps = adoptGRef(gst_caps_from_string(Caps()));
217         auto decoders = gst_element_factory_list_filter(all_decoders,
218             caps.get(), GST_PAD_SINK, FALSE);
219
220         gst_plugin_feature_list_free(all_decoders);
221         gst_plugin_feature_list_free(decoders);
222
223         return decoders != nullptr;
224     }
225
226     GstFlowReturn newSampleCallback(GstElement* sink)
227     {
228         auto sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
229         auto buffer = gst_sample_get_buffer(sample);
230
231         {
232             auto locker = holdLock(m_bufferMapLock);
233             // Make sure that the frame.timestamp == previsouly input_frame._timeStamp
234             // as it is required by the VideoDecoder baseclass.
235             GST_BUFFER_DTS(buffer) = m_dtsPtsMap[GST_BUFFER_PTS(buffer)];
236             m_dtsPtsMap.erase(GST_BUFFER_PTS(buffer));
237         }
238         auto frame(LibWebRTCVideoFrameFromGStreamerSample(sample, webrtc::kVideoRotation_0));
239         GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE;
240         GST_LOG_OBJECT(pipeline(), "Output decoded frame! %d -> %" GST_PTR_FORMAT,
241             frame->timestamp(), buffer);
242
243         m_imageReadyCb->Decoded(*frame.get(), absl::optional<int32_t>(), absl::optional<uint8_t>());
244
245         return GST_FLOW_OK;
246     }
247
248     virtual const gchar* Caps() = 0;
249     virtual webrtc::VideoCodecType CodecType() = 0;
250     const char* ImplementationName() const { return "GStreamer"; }
251     virtual const gchar* Name() = 0;
252
253 protected:
254     GRefPtr<GstCaps> m_caps;
255     gint m_pictureId;
256
257 private:
258     static GstFlowReturn newSampleCallbackTramp(GstElement* sink, GStreamerVideoDecoder* enc)
259     {
260         return enc->newSampleCallback(sink);
261     }
262
263     GRefPtr<GstElement> m_pipeline;
264     GstElement* m_src;
265
266     GstVideoInfo m_info;
267     webrtc::DecodedImageCallback* m_imageReadyCb;
268
269     Lock m_bufferMapLock;
270     StdMap<GstClockTime, GstClockTime> m_dtsPtsMap;
271     GstClockTime m_firstBufferPts;
272     GstClockTime m_firstBufferDts;
273 };
274
275 class H264Decoder : public GStreamerVideoDecoder {
276 public:
277     H264Decoder() { }
278     const gchar* Caps() final { return "video/x-h264"; }
279     const gchar* Name() final { return cricket::kH264CodecName; }
280     webrtc::VideoCodecType CodecType() final { return webrtc::kVideoCodecH264; }
281 };
282
283 class VP8Decoder : public GStreamerVideoDecoder {
284 public:
285     VP8Decoder() { }
286     const gchar* Caps() final { return "video/x-vp8"; }
287     const gchar* Name() final { return cricket::kVp8CodecName; }
288     webrtc::VideoCodecType CodecType() final { return webrtc::kVideoCodecVP8; }
289 };
290
291 std::unique_ptr<webrtc::VideoDecoder> GStreamerVideoDecoderFactory::CreateVideoDecoder(const webrtc::SdpVideoFormat& format)
292 {
293     GStreamerVideoDecoder* dec;
294
295     if (format.name == cricket::kH264CodecName)
296         dec = new H264Decoder();
297     else if (format.name == cricket::kVp8CodecName)
298         dec = new VP8Decoder();
299     else {
300         GST_ERROR("Could not create decoder for %s", format.name.c_str());
301
302         return nullptr;
303     }
304
305     return std::unique_ptr<webrtc::VideoDecoder>(dec);
306 }
307
308 GStreamerVideoDecoderFactory::GStreamerVideoDecoderFactory()
309 {
310     static std::once_flag debugRegisteredFlag;
311
312     std::call_once(debugRegisteredFlag, [] {
313         GST_DEBUG_CATEGORY_INIT(webkit_webrtcdec_debug, "webkitlibwebrtcvideodecoder", 0, "WebKit WebRTC video decoder");
314     });
315 }
316 std::vector<webrtc::SdpVideoFormat> GStreamerVideoDecoderFactory::GetSupportedFormats() const
317 {
318     std::vector<webrtc::SdpVideoFormat> formats;
319
320     VP8Decoder().AddDecoderIfSupported(formats);
321     H264Decoder().AddDecoderIfSupported(formats);
322
323     return formats;
324 }
325 }
326 #endif