Title: [237801] trunk
Revision
237801
Author
[email protected]
Date
2018-11-05 07:09:54 -0800 (Mon, 05 Nov 2018)

Log Message

[GStreamer][WebRTC] Add webrtcencoder bin to cleanup and refactor the way we set encoders
https://bugs.webkit.org/show_bug.cgi?id=190674

Patch by Thibault Saunier <[email protected]> on 2018-11-05
Reviewed by Philippe Normand.

webrtcencoder is a simple GstBin with a set of well known GStreamer encoders which
it can use to implement encoding for different formats exposing a trimmed down unified API.

It also adds proper handling of H264 profiles.

The added files follow GStreamer coding style as we aim at upstreaming the element
in the future.

Source/WebCore:

This is a refactoring so current tests already cover it.

* platform/GStreamer.cmake:
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::MediaPlayerPrivateGStreamerBase::initializeGStreamerAndRegisterWebKitElements):
* platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp: Added.
(gst_webrtc_video_encoder_get_property):
(gst_webrtc_video_encoder_set_bitrate):
(gst_webrtc_video_encoder_set_format):
(gst_webrtc_video_encoder_set_property):
(register_known_encoder):
(setup_x264enc):
(setup_vp8enc):
(setup_openh264enc):
(set_bitrate_kbit_per_sec):
(set_bitrate_bit_per_sec):
(gst_webrtc_video_encoder_class_init):
(gst_webrtc_video_encoder_init):
* platform/mediastream/libwebrtc/GStreamerVideoEncoder.h: Added.
* platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp:
(WebCore::GStreamerVideoEncoder::GStreamerVideoEncoder):
(WebCore::GStreamerVideoEncoder::InitEncode):
(WebCore::GStreamerVideoEncoder::createEncoder):
(WebCore::GStreamerVideoEncoder::AddCodecIfSupported):
(WebCore::GStreamerVideoEncoder::ImplementationName const):
(WebCore::GStreamerVideoEncoder::SetRestrictionCaps):

Tools:

Reviewed by Philippe Normand.

* Scripts/webkitpy/style/checker.py:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (237800 => 237801)


--- trunk/Source/WebCore/ChangeLog	2018-11-05 15:05:39 UTC (rev 237800)
+++ trunk/Source/WebCore/ChangeLog	2018-11-05 15:09:54 UTC (rev 237801)
@@ -1,5 +1,47 @@
 2018-11-05  Thibault Saunier  <[email protected]>
 
+        [GStreamer][WebRTC] Add webrtcencoder bin to cleanup and refactor the way we set encoders
+        https://bugs.webkit.org/show_bug.cgi?id=190674
+
+        Reviewed by Philippe Normand.
+
+        webrtcencoder is a simple GstBin with a set of well known GStreamer encoders which
+        it can use to implement encoding for different formats exposing a trimmed down unified API.
+
+        It also adds proper handling of H264 profiles.
+
+        The added files follow GStreamer coding style as we aim at upstreaming the element
+        in the future.
+
+        This is a refactoring so current tests already cover it.
+
+        * platform/GStreamer.cmake:
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerBase::initializeGStreamerAndRegisterWebKitElements):
+        * platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp: Added.
+        (gst_webrtc_video_encoder_get_property):
+        (gst_webrtc_video_encoder_set_bitrate):
+        (gst_webrtc_video_encoder_set_format):
+        (gst_webrtc_video_encoder_set_property):
+        (register_known_encoder):
+        (setup_x264enc):
+        (setup_vp8enc):
+        (setup_openh264enc):
+        (set_bitrate_kbit_per_sec):
+        (set_bitrate_bit_per_sec):
+        (gst_webrtc_video_encoder_class_init):
+        (gst_webrtc_video_encoder_init):
+        * platform/mediastream/libwebrtc/GStreamerVideoEncoder.h: Added.
+        * platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp:
+        (WebCore::GStreamerVideoEncoder::GStreamerVideoEncoder):
+        (WebCore::GStreamerVideoEncoder::InitEncode):
+        (WebCore::GStreamerVideoEncoder::createEncoder):
+        (WebCore::GStreamerVideoEncoder::AddCodecIfSupported):
+        (WebCore::GStreamerVideoEncoder::ImplementationName const):
+        (WebCore::GStreamerVideoEncoder::SetRestrictionCaps):
+
+2018-11-05  Thibault Saunier  <[email protected]>
+
         [GStreamer][WebRTC] properly mark H.264 stream type in the "decoder"
         https://bugs.webkit.org/show_bug.cgi?id=190676
 

Modified: trunk/Source/WebCore/platform/GStreamer.cmake (237800 => 237801)


--- trunk/Source/WebCore/platform/GStreamer.cmake	2018-11-05 15:05:39 UTC (rev 237800)
+++ trunk/Source/WebCore/platform/GStreamer.cmake	2018-11-05 15:09:54 UTC (rev 237801)
@@ -34,6 +34,7 @@
         platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp
 
         platform/mediastream/libwebrtc/GStreamerVideoDecoderFactory.cpp
+        platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp
         platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp
         platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp
 

Added: trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp (0 => 237801)


--- trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp	2018-11-05 15:09:54 UTC (rev 237801)
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2018 Metrological Group B.V.
+ * Copyright (C) 2018 Igalia S.L. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* NOTE: This file respects GStreamer coding style as we might want to upstream
+ * that element in the future */
+
+#include "config.h"
+
+#if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
+#include "GStreamerVideoEncoder.h"
+
+GST_DEBUG_CATEGORY (gst_webrtcenc_debug);
+#define GST_CAT_DEFAULT gst_webrtcenc_debug
+
+#define KBIT_TO_BIT 1024
+
+static GstStaticPadTemplate sinkTemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-raw(ANY);"));
+
+static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-h264;video/x-vp8"));
+
+typedef void (*SetBitrateFunc) (GObject * encoder, const gchar * propname,
+    gint bitrate);
+typedef void (*SetupEncoder) (GObject * encoder);
+typedef struct
+{
+  gboolean avalaible;
+  GstCaps *caps;
+  const gchar *name;
+  const gchar *parser_name;
+  GstCaps *encoded_format;
+  SetBitrateFunc setBitrate;
+  SetupEncoder setupEncoder;
+  const gchar *bitrate_propname;
+} EncoderDefinition;
+
+typedef enum
+{
+  ENCODER_NONE = 0,
+  ENCODER_X264,
+  ENCODER_OPENH264,
+  ENCODER_VP8,
+  ENCODER_LAST,
+} EncoderId;
+
+EncoderDefinition encoders[ENCODER_LAST] = {
+  FALSE,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+typedef struct
+{
+  EncoderId encoderId;
+  GstElement *encoder;
+  GstElement *parser;
+  GstElement *capsfilter;
+  guint bitrate;
+} GstWebrtcVideoEncoderPrivate;
+
+/*  *INDENT-OFF* */
+G_DEFINE_TYPE_WITH_PRIVATE (GstWebrtcVideoEncoder, gst_webrtc_video_encoder,
+    GST_TYPE_BIN)
+#define PRIV(self) ((GstWebrtcVideoEncoderPrivate*)gst_webrtc_video_encoder_get_instance_private(self))
+/*  *INDENT-ON* */
+
+enum
+{
+  PROP_0,
+  PROP_FORMAT,
+  PROP_ENCODER,
+  PROP_BITRATE,
+  N_PROPS
+};
+
+static void
+gst_webrtc_video_encoder_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_webrtc_video_encoder_parent_class)->finalize (object);
+}
+
+static void
+gst_webrtc_video_encoder_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstWebrtcVideoEncoder *self = GST_WEBRTC_VIDEO_ENCODER (object);
+  GstWebrtcVideoEncoderPrivate *priv = PRIV (self);
+
+  switch (prop_id) {
+    case PROP_FORMAT:
+      if (priv->encoderId != ENCODER_NONE)
+        g_value_set_boxed (value, encoders[priv->encoderId].caps);
+      else
+        g_value_set_boxed (value, NULL);
+      break;
+    case PROP_ENCODER:
+      g_value_set_object (value, priv->encoder);
+      break;
+    case PROP_BITRATE:
+      g_value_set_uint (value, priv->bitrate);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_webrtc_video_encoder_set_bitrate (GstWebrtcVideoEncoder * self,
+    guint bitrate)
+{
+  GstWebrtcVideoEncoderPrivate *priv = PRIV (self);
+
+  priv->bitrate = bitrate;
+  if (priv->encoder) {
+    encoders[priv->encoderId].setBitrate (G_OBJECT (priv->encoder),
+        encoders[priv->encoderId].bitrate_propname, priv->bitrate);
+  }
+}
+
+static void
+gst_webrtc_video_encoder_set_format (GstWebrtcVideoEncoder * self,
+    const GstCaps * caps)
+{
+  gint i;
+  GstWebrtcVideoEncoderPrivate *priv = PRIV (self);
+  g_return_if_fail (priv->encoderId == ENCODER_NONE);
+  g_return_if_fail (caps);
+
+  for (i = 1; i < ENCODER_LAST; i++) {
+    if (encoders[i].avalaible
+        && gst_caps_can_intersect (encoders[i].caps, caps)) {
+      GstPad *tmppad;
+      priv->encoderId = (EncoderId) i;
+      priv->encoder = gst_element_factory_make (encoders[i].name, NULL);
+      encoders[priv->encoderId].setupEncoder (G_OBJECT (priv->encoder));
+
+      if (encoders[i].parser_name)
+        priv->parser = gst_element_factory_make (encoders[i].parser_name, NULL);
+
+      if (encoders[i].encoded_format) {
+        priv->capsfilter = gst_element_factory_make ("capsfilter", NULL);
+        g_object_set (priv->capsfilter, "caps", encoders[i].encoded_format,
+            NULL);
+      }
+
+      gst_bin_add (GST_BIN (self), priv->encoder);
+
+      tmppad = gst_element_get_static_pad (priv->encoder, "sink");
+      gst_ghost_pad_set_target (GST_GHOST_PAD (GST_ELEMENT (self)->
+              sinkpads->data), tmppad);
+      gst_object_unref (tmppad);
+
+      tmppad = gst_element_get_static_pad (priv->encoder, "src");
+      if (priv->parser) {
+        gst_bin_add (GST_BIN (self), priv->parser);
+        gst_element_link (priv->encoder, priv->parser);
+        gst_object_unref (tmppad);
+        tmppad = gst_element_get_static_pad (priv->parser, "src");
+      }
+
+      if (priv->capsfilter) {
+        GstPad *tmppad2 = gst_element_get_static_pad (priv->capsfilter, "sink");
+
+        gst_bin_add (GST_BIN (self), priv->capsfilter);
+        gst_pad_link (tmppad, tmppad2);
+        gst_object_unref (tmppad);
+        tmppad = gst_element_get_static_pad (priv->capsfilter, "src");
+        gst_object_unref (tmppad2);
+      }
+
+      g_assert (gst_ghost_pad_set_target (GST_GHOST_PAD (GST_ELEMENT
+                  (self)->srcpads->data), tmppad));
+      gst_object_unref (tmppad);
+
+      gst_webrtc_video_encoder_set_bitrate (self, priv->bitrate);
+      return;
+    }
+  }
+
+  GST_ERROR ("No encoder found for format %" GST_PTR_FORMAT, caps);
+}
+
+static void
+gst_webrtc_video_encoder_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstWebrtcVideoEncoder *self = GST_WEBRTC_VIDEO_ENCODER (object);
+
+  switch (prop_id) {
+    case PROP_FORMAT:
+      gst_webrtc_video_encoder_set_format (self, gst_value_get_caps (value));
+      break;
+    case PROP_BITRATE:
+      gst_webrtc_video_encoder_set_bitrate (self, g_value_get_uint (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+register_known_encoder (EncoderId encId, const gchar * name,
+    const gchar * parser_name, const gchar * caps, const gchar * encoded_format,
+    SetupEncoder setupEncoder, const gchar * bitrate_propname,
+    SetBitrateFunc setBitrate)
+{
+  GstPluginFeature *feature =
+      gst_registry_lookup_feature (gst_registry_get (), name);
+  if (!feature) {
+    GST_WARNING ("Could not find %s", name);
+    encoders[encId].avalaible = FALSE;
+
+    return;
+  }
+  gst_object_unref (feature);
+
+  encoders[encId].avalaible = TRUE;
+  encoders[encId].name = name;
+  encoders[encId].parser_name = parser_name;
+  encoders[encId].caps = gst_caps_from_string (caps);
+  if (encoded_format)
+    encoders[encId].encoded_format = gst_caps_from_string (encoded_format);
+  else
+    encoders[encId].encoded_format = NULL;
+  encoders[encId].setupEncoder = setupEncoder;
+  encoders[encId].bitrate_propname = bitrate_propname;
+  encoders[encId].setBitrate = setBitrate;
+}
+
+static void
+setup_x264enc (GObject * encoder)
+{
+  gst_util_set_object_arg (encoder, "tune", "zerolatency");
+}
+
+static void
+setup_vp8enc (GObject * encoder)
+{
+  gst_preset_load_preset (GST_PRESET (encoder), "Profile Realtime");
+}
+
+static void
+setup_openh264enc (GObject *)
+{
+}
+
+static void
+set_bitrate_kbit_per_sec (GObject * encoder, const gchar * prop_name,
+    gint bitrate)
+{
+  g_object_set (encoder, prop_name, bitrate, NULL);
+}
+
+static void
+set_bitrate_bit_per_sec (GObject * encoder, const gchar * prop_name,
+    gint bitrate)
+{
+  g_object_set (encoder, prop_name, bitrate * KBIT_TO_BIT, NULL);
+}
+
+static void
+gst_webrtc_video_encoder_class_init (GstWebrtcVideoEncoderClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_webrtcenc_debug, "webrtcencoder", 0,
+      "Video encoder for WebRTC");
+
+  object_class->finalize = gst_webrtc_video_encoder_finalize;
+  object_class->get_property = gst_webrtc_video_encoder_get_property;
+  object_class->set_property = gst_webrtc_video_encoder_set_property;
+
+  g_object_class_install_property (object_class, PROP_FORMAT,
+      g_param_spec_boxed ("format", "Format as caps",
+          "Set the caps of the format to be used.",
+          GST_TYPE_CAPS,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (object_class, PROP_ENCODER,
+      g_param_spec_object ("encoder", "The actual encoder element",
+          "The encoder element", GST_TYPE_ELEMENT,
+          (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property (object_class, PROP_BITRATE,
+      g_param_spec_uint ("bitrate", "Bitrate",
+          "The bitrate in kbit per second", 0, G_MAXINT, 2048,
+          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+              G_PARAM_CONSTRUCT)));
+
+  register_known_encoder (ENCODER_X264, "x264enc", "h264parse", "video/x-h264",
+      "video/x-h264,alignment=au,stream-format=byte-stream,profile=""
+      setup_x264enc, "bitrate", set_bitrate_kbit_per_sec);
+  register_known_encoder (ENCODER_OPENH264, "openh264enc", "h264parse",
+      "video/x-h264",
+      "video/x-h264,alignment=au,stream-format=byte-stream,profile=""
+      setup_openh264enc, "bitrate", set_bitrate_kbit_per_sec);
+  register_known_encoder (ENCODER_VP8, "vp8enc", NULL, "video/x-vp8", NULL,
+      setup_vp8enc, "target-bitrate", set_bitrate_bit_per_sec);
+}
+
+static void
+gst_webrtc_video_encoder_init (GstWebrtcVideoEncoder * self)
+{
+  GstWebrtcVideoEncoderPrivate *priv = PRIV (self);
+
+  priv->encoderId = ENCODER_NONE;
+  gst_element_add_pad (GST_ELEMENT (self),
+      gst_ghost_pad_new_no_target_from_template ("sink",
+          gst_static_pad_template_get (&sinkTemplate)));
+
+  gst_element_add_pad (GST_ELEMENT (self),
+      gst_ghost_pad_new_no_target_from_template ("src",
+          gst_static_pad_template_get (&srcTemplate)));
+}
+
+#endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)

Added: trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.h (0 => 237801)


--- trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.h	2018-11-05 15:09:54 UTC (rev 237801)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 Metrological Group B.V.
+ * Copyright (C) 2018 Igalia S.L. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WEBRTC_VIDEO_ENCODER (gst_webrtc_video_encoder_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (GstWebrtcVideoEncoder, gst_webrtc_video_encoder, GST, WEBRTC_VIDEO_ENCODER, GstBin)
+
+struct _GstWebrtcVideoEncoderClass
+{
+  GstBinClass parent_class;
+};
+
+G_END_DECLS

Modified: trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp (237800 => 237801)


--- trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp	2018-11-05 15:05:39 UTC (rev 237800)
+++ trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp	2018-11-05 15:09:54 UTC (rev 237801)
@@ -23,6 +23,7 @@
 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
 #include "GStreamerVideoEncoderFactory.h"
 
+#include "GStreamerVideoEncoder.h"
 #include "GStreamerVideoFrameLibWebRTC.h"
 #include "webrtc/common_video/h264/h264_common.h"
 #include "webrtc/common_video/h264/profile_level_id.h"
@@ -63,13 +64,11 @@
     GStreamerVideoEncoder(const webrtc::SdpVideoFormat&)
         : m_firstFramePts(GST_CLOCK_TIME_NONE)
         , m_restrictionCaps(adoptGRef(gst_caps_new_empty_simple("video/x-raw")))
-        , m_bitrateSetter(nullptr)
     {
     }
     GStreamerVideoEncoder()
         : m_firstFramePts(GST_CLOCK_TIME_NONE)
         , m_restrictionCaps(adoptGRef(gst_caps_new_empty_simple("video/x-raw")))
-        , m_bitrateSetter(nullptr)
     {
     }
 
@@ -83,8 +82,8 @@
 
         SetRestrictionCaps(WTFMove(caps));
 
-        if (m_bitrateSetter && m_encoder)
-            m_bitrateSetter(m_encoder, newBitrate);
+        if (m_encoder)
+            g_object_set(m_encoder, "bitrate", newBitrate, nullptr);
 
         return WEBRTC_VIDEO_CODEC_OK;
     }
@@ -118,20 +117,26 @@
         m_pipeline = makeElement("pipeline");
 
         connectSimpleBusMessageCallback(m_pipeline.get());
-        auto encodebin = createEncoder(&m_encoder).leakRef();
-        ASSERT(m_encoder);
-        m_bitrateSetter = getBitrateSetter(gst_element_get_factory(m_encoder));
+        auto encoder = createEncoder();
+        ASSERT(encoder);
+        m_encoder = encoder.get();
 
         m_src = makeElement("appsrc");
         g_object_set(m_src, "is-live", true, "format", GST_FORMAT_TIME, nullptr);
 
-        auto capsfilter = CreateFilter();
+        auto videoconvert = makeElement("videoconvert");
+        auto videorate = makeElement("videorate");
         auto sink = makeElement("appsink");
         gst_app_sink_set_emit_signals(GST_APP_SINK(sink), TRUE);
         g_signal_connect(sink, "new-sample", G_CALLBACK(newSampleCallbackTramp), this);
 
-        gst_bin_add_many(GST_BIN(m_pipeline.get()), m_src, encodebin, capsfilter, sink, nullptr);
-        if (!gst_element_link_many(m_src, encodebin, capsfilter, sink, nullptr))
+        auto name = String::format("%s_enc_rawcapsfilter_%p", Name(), this);
+        m_capsFilter = gst_element_factory_make("capsfilter", name.utf8().data());
+        if (m_restrictionCaps)
+            g_object_set(m_capsFilter, "caps", m_restrictionCaps.get(), nullptr);
+
+        gst_bin_add_many(GST_BIN(m_pipeline.get()), m_src, videorate, videoconvert, m_capsFilter, encoder.leakRef(), sink, nullptr);
+        if (!gst_element_link_many(m_src, videorate, videoconvert, m_capsFilter, m_encoder, sink, nullptr))
             ASSERT_NOT_REACHED();
 
         gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING);
@@ -144,11 +149,6 @@
         return true;
     }
 
-    virtual GstElement* CreateFilter()
-    {
-        return makeElement("capsfilter");
-    }
-
     int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* callback) final
     {
         m_imageReadyCb = callback;
@@ -160,12 +160,16 @@
     {
         m_encodedFrame._buffer = nullptr;
         m_encodedImageBuffer.reset();
-        GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
-        gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
+        if (m_pipeline) {
+            GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
+            gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
 
-        gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
-        m_src = nullptr;
-        m_pipeline = nullptr;
+            gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
+            m_src = nullptr;
+            m_encoder = nullptr;
+            m_capsFilter = nullptr;
+            m_pipeline = nullptr;
+        }
 
         return WEBRTC_VIDEO_CODEC_OK;
     }
@@ -255,75 +259,21 @@
         return GST_FLOW_OK;
     }
 
-#define RETURN_BITRATE_SETTER_IF_MATCHES(regex, propertyName, bitrateMultiplier, unit)                 \
-    if (g_regex_match(regex.get(), factoryName, static_cast<GRegexMatchFlags>(0), nullptr)) {          \
-        GST_INFO_OBJECT(encoderFactory, "Detected as having a " #propertyName " property in " unit); \
-        return [](GstElement* encoder, uint32_t bitrate)                                               \
-            {                                                                                          \
-                g_object_set(encoder, propertyName, bitrate * bitrateMultiplier, nullptr);            \
-            };                                                                                         \
-    }
-
-    // GStreamer doesn't have a unified encoder API and the encoders have their
-    // own semantics and naming to set the bitrate, this is a best effort to handle
-    // setting bitrate for the well known encoders.
-    // See https://bugzilla.gnome.org/show_bug.cgi?id=796716
-    BitrateSetter getBitrateSetter(GstElementFactory* encoderFactory)
+    GRefPtr<GstElement> createEncoder(void)
     {
-        static std::once_flag regexRegisteredFlag;
+        GRefPtr<GstElement> encoder = nullptr;
+        GstElement* webrtcencoder = GST_ELEMENT(g_object_ref_sink(gst_element_factory_make("webrtcvideoencoder", NULL)));
 
-        std::call_once(regexRegisteredFlag, [] {
-            targetBitrateBitPerSec = g_regex_new("^vp.enc$|^omx.*enc$", static_cast<GRegexCompileFlags>(0), static_cast<GRegexMatchFlags>(0), nullptr);
-            bitrateBitPerSec = g_regex_new("^openh264enc$", static_cast<GRegexCompileFlags>(0), static_cast<GRegexMatchFlags>(0), nullptr);
-            bitrateKBitPerSec = g_regex_new("^x264enc$|vaapi.*enc$", static_cast<GRegexCompileFlags>(0), static_cast<GRegexMatchFlags>(0), nullptr);
-            ASSERT(targetBitrateBitPerSec.get() && bitrateBitPerSec.get() && bitrateKBitPerSec.get());
-        });
+        g_object_set(webrtcencoder, "format", adoptGRef(gst_caps_from_string(Caps())).get(), NULL);
+        g_object_get(webrtcencoder, "encoder", &encoder.outPtr(), NULL);
 
-        auto factoryName = GST_OBJECT_NAME(encoderFactory);
-        RETURN_BITRATE_SETTER_IF_MATCHES(targetBitrateBitPerSec, "target-bitrate", KBIT_TO_BIT, "Bits Per Second")
-        RETURN_BITRATE_SETTER_IF_MATCHES(bitrateBitPerSec, "bitrate", KBIT_TO_BIT, "Bits Per Second")
-        RETURN_BITRATE_SETTER_IF_MATCHES(bitrateKBitPerSec, "bitrate", 1, "KBits Per Second")
+        if (!encoder) {
+            GST_INFO("No encoder found for %s", Caps());
 
-        GST_WARNING_OBJECT(encoderFactory, "unkonwn encoder, can't set bitrates on it");
-        return nullptr;
-    }
-#undef RETURN_BITRATE_SETTER_IF_MATCHES
-
-    GRefPtr<GstElement> createEncoder(GstElement** encoder)
-    {
-        GstElement* enc = nullptr;
-
-        m_profile = GST_ENCODING_PROFILE(gst_encoding_video_profile_new(
-            adoptGRef(gst_caps_from_string(Caps())).get(),
-            ProfileName(),
-            gst_caps_ref(m_restrictionCaps.get()),
-            1));
-        GRefPtr<GstElement> encodebin = makeElement("encodebin");
-
-        if (!encodebin.get()) {
-            GST_ERROR("No encodebin present... can't use GStreamer based encoders");
             return nullptr;
         }
-        g_object_set(encodebin.get(), "profile", m_profile.get(), nullptr);
 
-        for (GList* tmp = GST_BIN_CHILDREN(encodebin.get()); tmp; tmp = tmp->next) {
-            GstElement* elem = GST_ELEMENT(tmp->data);
-            GstElementFactory* factory = gst_element_get_factory((elem));
-
-            if (!factory || !gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER))
-                continue;
-
-            enc = elem;
-            break;
-        }
-
-        if (!enc)
-            return nullptr;
-
-        if (encoder)
-            *encoder = enc;
-
-        return encodebin;
+        return webrtcencoder;
     }
 
     void AddCodecIfSupported(std::vector<webrtc::SdpVideoFormat>* supportedFormats)
@@ -330,7 +280,7 @@
     {
         GstElement* encoder;
 
-        if (createEncoder(&encoder).get() != nullptr) {
+        if (createEncoder().get() != nullptr) {
             webrtc::SdpVideoFormat format = ConfigureSupportedCodec(encoder);
 
             supportedFormats->push_back(format);
@@ -380,9 +330,12 @@
 
     const char* ImplementationName() const
     {
+        GRefPtr<GstElement> encoderImplementation;
         g_return_val_if_fail(m_encoder, nullptr);
 
-        return GST_OBJECT_NAME(gst_element_get_factory(m_encoder));
+        g_object_get(m_encoder, "encoder", &encoderImplementation.outPtr(), nullptr);
+
+        return GST_OBJECT_NAME(gst_element_get_factory(encoderImplementation.get()));
     }
 
     virtual const gchar* Name() = 0;
@@ -389,8 +342,8 @@
 
     void SetRestrictionCaps(GRefPtr<GstCaps> caps)
     {
-        if (caps && m_profile.get() && gst_caps_is_equal(m_restrictionCaps.get(), caps.get()))
-            g_object_set(m_profile.get(), "restriction-caps", caps.get(), nullptr);
+        if (m_restrictionCaps)
+            g_object_set(m_capsFilter, "caps", m_restrictionCaps.get(), nullptr);
 
         m_restrictionCaps = caps;
     }
@@ -404,12 +357,11 @@
     GRefPtr<GstElement> m_pipeline;
     GstElement* m_src;
     GstElement* m_encoder;
+    GstElement* m_capsFilter;
 
     webrtc::EncodedImageCallback* m_imageReadyCb;
     GstClockTime m_firstFramePts;
     GRefPtr<GstCaps> m_restrictionCaps;
-    GRefPtr<GstEncodingProfile> m_profile;
-    BitrateSetter m_bitrateSetter;
     webrtc::EncodedImage m_encodedFrame;
     std::unique_ptr<uint8_t[]> m_encodedImageBuffer;
     size_t m_encodedImageBufferSize;
@@ -483,18 +435,6 @@
         }
     }
 
-    GstElement* CreateFilter() final
-    {
-        GstElement* filter = makeElement("capsfilter");
-        auto caps = adoptGRef(gst_caps_new_simple(Caps(),
-            "alignment", G_TYPE_STRING, "au",
-            "stream-format", G_TYPE_STRING, "byte-stream",
-            nullptr));
-        g_object_set(filter, "caps", caps.get(), nullptr);
-
-        return filter;
-    }
-
     webrtc::SdpVideoFormat ConfigureSupportedCodec(GstElement*) final
     {
         // TODO- Create from encoder src pad caps template
@@ -558,6 +498,7 @@
 
     std::call_once(debugRegisteredFlag, [] {
         GST_DEBUG_CATEGORY_INIT(webkit_webrtcenc_debug, "webkitlibwebrtcvideoencoder", 0, "WebKit WebRTC video encoder");
+        gst_element_register(nullptr, "webrtcvideoencoder", GST_RANK_PRIMARY, GST_TYPE_WEBRTC_VIDEO_ENCODER);
     });
 }
 

Modified: trunk/Tools/ChangeLog (237800 => 237801)


--- trunk/Tools/ChangeLog	2018-11-05 15:05:39 UTC (rev 237800)
+++ trunk/Tools/ChangeLog	2018-11-05 15:09:54 UTC (rev 237801)
@@ -1,3 +1,22 @@
+2018-11-05  Thibault Saunier  <[email protected]>
+
+        [GStreamer][WebRTC] Add webrtcencoder bin to cleanup and refactor the way we set encoders
+        https://bugs.webkit.org/show_bug.cgi?id=190674
+
+        Reviewed by Philippe Normand.
+
+        webrtcencoder is a simple GstBin with a set of well known GStreamer encoders which
+        it can use to implement encoding for different formats exposing a trimmed down unified API.
+
+        It also adds proper handling of H264 profiles.
+
+        The added files follow GStreamer coding style as we aim at upstreaming the element
+        in the future.
+
+        Reviewed by Philippe Normand.
+
+        * Scripts/webkitpy/style/checker.py:
+
 2018-11-05  Michael Catanzaro  <[email protected]>
 
         [WPE][GTK] API test /webkit/WebKitSettings/webkit-settings is failing

Modified: trunk/Tools/Scripts/webkitpy/style/checker.py (237800 => 237801)


--- trunk/Tools/Scripts/webkitpy/style/checker.py	2018-11-05 15:05:39 UTC (rev 237800)
+++ trunk/Tools/Scripts/webkitpy/style/checker.py	2018-11-05 15:09:54 UTC (rev 237801)
@@ -237,6 +237,19 @@
       "-whitespace/declaration",
       "-whitespace/indent"]),
 
+    ([  # Files following GStreamer coding style (for a simpler upstreaming process for example)
+      os.path.join('Source', 'WebCore', 'platform', 'mediastream', 'libwebrtc', 'GStreamerVideoEncoder.cpp'),
+      os.path.join('Source', 'WebCore', 'platform', 'mediastream', 'libwebrtc', 'GStreamerVideoEncoder.h'),
+     ],
+     ["-whitespace/indent",
+      "-whitespace/declaration",
+      "-whitespace/parens",
+      "-readability/null",
+      "-whitespace/braces",
+      "-readability/naming/underscores",
+      "-readability/enum_casing",
+     ]),
+
     ([
       # There is no way to avoid the symbols __jit_debug_register_code
       # and __jit_debug_descriptor when integrating with gdb.
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to