<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[237801] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/237801">237801</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2018-11-05 07:09:54 -0800 (Mon, 05 Nov 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>[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 <tsaunier@igalia.com> 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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformGStreamercmake">trunk/Source/WebCore/platform/GStreamer.cmake</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamlibwebrtcGStreamerVideoEncoderFactorycpp">trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptswebkitpystylecheckerpy">trunk/Tools/Scripts/webkitpy/style/checker.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreplatformmediastreamlibwebrtcGStreamerVideoEncodercpp">trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamlibwebrtcGStreamerVideoEncoderh">trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (237800 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,5 +1,47 @@
</span><span class="cx"> 2018-11-05  Thibault Saunier  <tsaunier@igalia.com>
</span><span class="cx"> 
</span><ins>+        [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  <tsaunier@igalia.com>
+
</ins><span class="cx">         [GStreamer][WebRTC] properly mark H.264 stream type in the "decoder"
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=190676
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformGStreamercmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/GStreamer.cmake (237800 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx">         platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp
</span><span class="cx"> 
</span><span class="cx">         platform/mediastream/libwebrtc/GStreamerVideoDecoderFactory.cpp
</span><ins>+        platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp
</ins><span class="cx">         platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp
</span><span class="cx">         platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamlibwebrtcGStreamerVideoEncodercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.cpp (0 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,343 @@
</span><ins>+/*
+ * 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=baseline",
+      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=baseline",
+      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)
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamlibwebrtcGStreamerVideoEncoderh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoder.h (0 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+/*
+ * 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
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamlibwebrtcGStreamerVideoEncoderFactorycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/libwebrtc/GStreamerVideoEncoderFactory.cpp (237800 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
</span><span class="cx"> #include "GStreamerVideoEncoderFactory.h"
</span><span class="cx"> 
</span><ins>+#include "GStreamerVideoEncoder.h"
</ins><span class="cx"> #include "GStreamerVideoFrameLibWebRTC.h"
</span><span class="cx"> #include "webrtc/common_video/h264/h264_common.h"
</span><span class="cx"> #include "webrtc/common_video/h264/profile_level_id.h"
</span><span class="lines">@@ -63,13 +64,11 @@
</span><span class="cx">     GStreamerVideoEncoder(const webrtc::SdpVideoFormat&)
</span><span class="cx">         : m_firstFramePts(GST_CLOCK_TIME_NONE)
</span><span class="cx">         , m_restrictionCaps(adoptGRef(gst_caps_new_empty_simple("video/x-raw")))
</span><del>-        , m_bitrateSetter(nullptr)
</del><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     GStreamerVideoEncoder()
</span><span class="cx">         : m_firstFramePts(GST_CLOCK_TIME_NONE)
</span><span class="cx">         , m_restrictionCaps(adoptGRef(gst_caps_new_empty_simple("video/x-raw")))
</span><del>-        , m_bitrateSetter(nullptr)
</del><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -83,8 +82,8 @@
</span><span class="cx"> 
</span><span class="cx">         SetRestrictionCaps(WTFMove(caps));
</span><span class="cx"> 
</span><del>-        if (m_bitrateSetter && m_encoder)
-            m_bitrateSetter(m_encoder, newBitrate);
</del><ins>+        if (m_encoder)
+            g_object_set(m_encoder, "bitrate", newBitrate, nullptr);
</ins><span class="cx"> 
</span><span class="cx">         return WEBRTC_VIDEO_CODEC_OK;
</span><span class="cx">     }
</span><span class="lines">@@ -118,20 +117,26 @@
</span><span class="cx">         m_pipeline = makeElement("pipeline");
</span><span class="cx"> 
</span><span class="cx">         connectSimpleBusMessageCallback(m_pipeline.get());
</span><del>-        auto encodebin = createEncoder(&m_encoder).leakRef();
-        ASSERT(m_encoder);
-        m_bitrateSetter = getBitrateSetter(gst_element_get_factory(m_encoder));
</del><ins>+        auto encoder = createEncoder();
+        ASSERT(encoder);
+        m_encoder = encoder.get();
</ins><span class="cx"> 
</span><span class="cx">         m_src = makeElement("appsrc");
</span><span class="cx">         g_object_set(m_src, "is-live", true, "format", GST_FORMAT_TIME, nullptr);
</span><span class="cx"> 
</span><del>-        auto capsfilter = CreateFilter();
</del><ins>+        auto videoconvert = makeElement("videoconvert");
+        auto videorate = makeElement("videorate");
</ins><span class="cx">         auto sink = makeElement("appsink");
</span><span class="cx">         gst_app_sink_set_emit_signals(GST_APP_SINK(sink), TRUE);
</span><span class="cx">         g_signal_connect(sink, "new-sample", G_CALLBACK(newSampleCallbackTramp), this);
</span><span class="cx"> 
</span><del>-        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))
</del><ins>+        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))
</ins><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx"> 
</span><span class="cx">         gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING);
</span><span class="lines">@@ -144,11 +149,6 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    virtual GstElement* CreateFilter()
-    {
-        return makeElement("capsfilter");
-    }
-
</del><span class="cx">     int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* callback) final
</span><span class="cx">     {
</span><span class="cx">         m_imageReadyCb = callback;
</span><span class="lines">@@ -160,12 +160,16 @@
</span><span class="cx">     {
</span><span class="cx">         m_encodedFrame._buffer = nullptr;
</span><span class="cx">         m_encodedImageBuffer.reset();
</span><del>-        GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
-        gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
</del><ins>+        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);
</ins><span class="cx"> 
</span><del>-        gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
-        m_src = nullptr;
-        m_pipeline = nullptr;
</del><ins>+            gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
+            m_src = nullptr;
+            m_encoder = nullptr;
+            m_capsFilter = nullptr;
+            m_pipeline = nullptr;
+        }
</ins><span class="cx"> 
</span><span class="cx">         return WEBRTC_VIDEO_CODEC_OK;
</span><span class="cx">     }
</span><span class="lines">@@ -255,75 +259,21 @@
</span><span class="cx">         return GST_FLOW_OK;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-#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)
</del><ins>+    GRefPtr<GstElement> createEncoder(void)
</ins><span class="cx">     {
</span><del>-        static std::once_flag regexRegisteredFlag;
</del><ins>+        GRefPtr<GstElement> encoder = nullptr;
+        GstElement* webrtcencoder = GST_ELEMENT(g_object_ref_sink(gst_element_factory_make("webrtcvideoencoder", NULL)));
</ins><span class="cx"> 
</span><del>-        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());
-        });
</del><ins>+        g_object_set(webrtcencoder, "format", adoptGRef(gst_caps_from_string(Caps())).get(), NULL);
+        g_object_get(webrtcencoder, "encoder", &encoder.outPtr(), NULL);
</ins><span class="cx"> 
</span><del>-        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")
</del><ins>+        if (!encoder) {
+            GST_INFO("No encoder found for %s", Caps());
</ins><span class="cx"> 
</span><del>-        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");
</del><span class="cx">             return nullptr;
</span><span class="cx">         }
</span><del>-        g_object_set(encodebin.get(), "profile", m_profile.get(), nullptr);
</del><span class="cx"> 
</span><del>-        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;
</del><ins>+        return webrtcencoder;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void AddCodecIfSupported(std::vector<webrtc::SdpVideoFormat>* supportedFormats)
</span><span class="lines">@@ -330,7 +280,7 @@
</span><span class="cx">     {
</span><span class="cx">         GstElement* encoder;
</span><span class="cx"> 
</span><del>-        if (createEncoder(&encoder).get() != nullptr) {
</del><ins>+        if (createEncoder().get() != nullptr) {
</ins><span class="cx">             webrtc::SdpVideoFormat format = ConfigureSupportedCodec(encoder);
</span><span class="cx"> 
</span><span class="cx">             supportedFormats->push_back(format);
</span><span class="lines">@@ -380,9 +330,12 @@
</span><span class="cx"> 
</span><span class="cx">     const char* ImplementationName() const
</span><span class="cx">     {
</span><ins>+        GRefPtr<GstElement> encoderImplementation;
</ins><span class="cx">         g_return_val_if_fail(m_encoder, nullptr);
</span><span class="cx"> 
</span><del>-        return GST_OBJECT_NAME(gst_element_get_factory(m_encoder));
</del><ins>+        g_object_get(m_encoder, "encoder", &encoderImplementation.outPtr(), nullptr);
+
+        return GST_OBJECT_NAME(gst_element_get_factory(encoderImplementation.get()));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     virtual const gchar* Name() = 0;
</span><span class="lines">@@ -389,8 +342,8 @@
</span><span class="cx"> 
</span><span class="cx">     void SetRestrictionCaps(GRefPtr<GstCaps> caps)
</span><span class="cx">     {
</span><del>-        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);
</del><ins>+        if (m_restrictionCaps)
+            g_object_set(m_capsFilter, "caps", m_restrictionCaps.get(), nullptr);
</ins><span class="cx"> 
</span><span class="cx">         m_restrictionCaps = caps;
</span><span class="cx">     }
</span><span class="lines">@@ -404,12 +357,11 @@
</span><span class="cx">     GRefPtr<GstElement> m_pipeline;
</span><span class="cx">     GstElement* m_src;
</span><span class="cx">     GstElement* m_encoder;
</span><ins>+    GstElement* m_capsFilter;
</ins><span class="cx"> 
</span><span class="cx">     webrtc::EncodedImageCallback* m_imageReadyCb;
</span><span class="cx">     GstClockTime m_firstFramePts;
</span><span class="cx">     GRefPtr<GstCaps> m_restrictionCaps;
</span><del>-    GRefPtr<GstEncodingProfile> m_profile;
-    BitrateSetter m_bitrateSetter;
</del><span class="cx">     webrtc::EncodedImage m_encodedFrame;
</span><span class="cx">     std::unique_ptr<uint8_t[]> m_encodedImageBuffer;
</span><span class="cx">     size_t m_encodedImageBufferSize;
</span><span class="lines">@@ -483,18 +435,6 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    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;
-    }
-
</del><span class="cx">     webrtc::SdpVideoFormat ConfigureSupportedCodec(GstElement*) final
</span><span class="cx">     {
</span><span class="cx">         // TODO- Create from encoder src pad caps template
</span><span class="lines">@@ -558,6 +498,7 @@
</span><span class="cx"> 
</span><span class="cx">     std::call_once(debugRegisteredFlag, [] {
</span><span class="cx">         GST_DEBUG_CATEGORY_INIT(webkit_webrtcenc_debug, "webkitlibwebrtcvideoencoder", 0, "WebKit WebRTC video encoder");
</span><ins>+        gst_element_register(nullptr, "webrtcvideoencoder", GST_RANK_PRIMARY, GST_TYPE_WEBRTC_VIDEO_ENCODER);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (237800 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2018-11-05 15:05:39 UTC (rev 237800)
+++ trunk/Tools/ChangeLog       2018-11-05 15:09:54 UTC (rev 237801)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2018-11-05  Thibault Saunier  <tsaunier@igalia.com>
+
+        [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:
+
</ins><span class="cx"> 2018-11-05  Michael Catanzaro  <mcatanzaro@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         [WPE][GTK] API test /webkit/WebKitSettings/webkit-settings is failing
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpystylecheckerpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/style/checker.py (237800 => 237801)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -237,6 +237,19 @@
</span><span class="cx">       "-whitespace/declaration",
</span><span class="cx">       "-whitespace/indent"]),
</span><span class="cx"> 
</span><ins>+    ([  # 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",
+     ]),
+
</ins><span class="cx">     ([
</span><span class="cx">       # There is no way to avoid the symbols __jit_debug_register_code
</span><span class="cx">       # and __jit_debug_descriptor when integrating with gdb.
</span></span></pre>
</div>
</div>

</body>
</html>