videoencoder: add qos property
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Wed, 25 Oct 2017 09:41:02 +0000 (11:41 +0200)
committerMathieu Duponchelle <mathieu@centricular.com>
Wed, 25 Oct 2017 12:22:15 +0000 (14:22 +0200)
This new property control if the encoder base class should gather QoS
stats and if subclasses should use them by dropping late frames.

https://bugzilla.gnome.org/show_bug.cgi?id=789467

gst-libs/gst/video/gstvideoencoder.c
gst-libs/gst/video/gstvideoencoder.h
tests/check/libs/videoencoder.c

index 03c76b9..f872572 100644 (file)
  *   * Accept data in @handle_frame and provide encoded results to
  *      @gst_video_encoder_finish_frame.
  *
+ *
+ * The #GstVideoEncoder:qos property will enable the Quality-of-Service
+ * features of the encoder which gather statistics about the real-time
+ * performance of the downstream elements. If enabled, subclasses can
+ * use gst_video_encoder_get_max_encode_time() to check if input frames
+ * are already late and drop them right away to give a chance to the
+ * pipeline to catch up.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -108,6 +115,17 @@ GST_DEBUG_CATEGORY (videoencoder_debug);
     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VIDEO_ENCODER, \
         GstVideoEncoderPrivate))
 
+/* properties */
+
+#define DEFAULT_QOS                 FALSE
+
+enum
+{
+  PROP_0,
+  PROP_QOS,
+  PROP_LAST
+};
+
 struct _GstVideoEncoderPrivate
 {
   guint64 presentation_frame_number;
@@ -154,6 +172,7 @@ struct _GstVideoEncoderPrivate
   GstClockTime time_adjustment;
 
   /* QoS properties */
+  gint qos_enabled;             /* ATOMIC */
   gdouble proportion;           /* OBJECT_LOCK */
   GstClockTime earliest_time;   /* OBJECT_LOCK */
   GstClockTime qos_frame_duration;      /* OBJECT_LOCK */
@@ -274,6 +293,38 @@ gst_video_encoder_get_type (void)
 }
 
 static void
+gst_video_encoder_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoEncoder *sink = GST_VIDEO_ENCODER (object);
+
+  switch (prop_id) {
+    case PROP_QOS:
+      gst_video_encoder_set_qos_enabled (sink, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_video_encoder_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstVideoEncoder *sink = GST_VIDEO_ENCODER (object);
+
+  switch (prop_id) {
+    case PROP_QOS:
+      g_value_set_boolean (value, gst_video_encoder_is_qos_enabled (sink));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_video_encoder_class_init (GstVideoEncoderClass * klass)
 {
   GObjectClass *gobject_class;
@@ -289,6 +340,8 @@ gst_video_encoder_class_init (GstVideoEncoderClass * klass)
 
   g_type_class_add_private (klass, sizeof (GstVideoEncoderPrivate));
 
+  gobject_class->set_property = gst_video_encoder_set_property;
+  gobject_class->get_property = gst_video_encoder_get_property;
   gobject_class->finalize = gst_video_encoder_finalize;
 
   gstelement_class->change_state =
@@ -302,6 +355,11 @@ gst_video_encoder_class_init (GstVideoEncoderClass * klass)
   klass->sink_query = gst_video_encoder_sink_query_default;
   klass->src_query = gst_video_encoder_src_query_default;
   klass->transform_meta = gst_video_encoder_transform_meta_default;
+
+  g_object_class_install_property (gobject_class, PROP_QOS,
+      g_param_spec_boolean ("qos", "Qos",
+          "Handle Quality-of-Service events from downstream", DEFAULT_QOS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
 static GList *
@@ -1196,6 +1254,9 @@ gst_video_encoder_src_event_default (GstVideoEncoder * encoder,
       GstClockTimeDiff diff;
       GstClockTime timestamp;
 
+      if (!g_atomic_int_get (&priv->qos_enabled))
+        break;
+
       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
 
       GST_OBJECT_LOCK (encoder);
@@ -2585,6 +2646,9 @@ gst_video_encoder_set_min_pts (GstVideoEncoder * encoder, GstClockTime min_pts)
  * In particular, a negative result means encoding in time is no longer possible
  * and should therefore occur as soon/skippy as possible.
  *
+ * If no QoS events have been received from downstream, or if
+ * #GstVideoEncoder:qos is disabled this function returns #G_MAXINT64.
+ *
  * Returns: max decoding time.
  * Since: 1.14
  */
@@ -2595,6 +2659,9 @@ gst_video_encoder_get_max_encode_time (GstVideoEncoder *
   GstClockTimeDiff deadline;
   GstClockTime earliest_time;
 
+  if (!g_atomic_int_get (&encoder->priv->qos_enabled))
+    return G_MAXINT64;
+
   GST_OBJECT_LOCK (encoder);
   earliest_time = encoder->priv->earliest_time;
   if (GST_CLOCK_TIME_IS_VALID (earliest_time)
@@ -2612,3 +2679,41 @@ gst_video_encoder_get_max_encode_time (GstVideoEncoder *
 
   return deadline;
 }
+
+/**
+ * gst_video_encoder_set_qos_enabled:
+ * @encoder: the encoder
+ * @enabled: the new qos value.
+ *
+ * Configures @encoder to handle Quality-of-Service events from downstream.
+ * Since: 1.14
+ */
+void
+gst_video_encoder_set_qos_enabled (GstVideoEncoder * encoder, gboolean enabled)
+{
+  g_return_if_fail (GST_IS_VIDEO_ENCODER (encoder));
+
+  g_atomic_int_set (&encoder->priv->qos_enabled, enabled);
+}
+
+/**
+ * gst_video_encoder_is_qos_enabled:
+ * @encoder: the encoder
+ *
+ * Checks if @encoder is currently configured to handle Quality-of-Service
+ * events from downstream.
+ *
+ * Returns: %TRUE if the encoder is configured to perform Quality-of-Service.
+ * Since: 1.14
+ */
+gboolean
+gst_video_encoder_is_qos_enabled (GstVideoEncoder * encoder)
+{
+  gboolean res;
+
+  g_return_val_if_fail (GST_IS_VIDEO_ENCODER (encoder), FALSE);
+
+  res = g_atomic_int_get (&encoder->priv->qos_enabled);
+
+  return res;
+}
index 25bd877..18b1ba5 100644 (file)
@@ -369,6 +369,12 @@ GST_EXPORT
 void                 gst_video_encoder_set_min_pts(GstVideoEncoder *encoder, GstClockTime min_pts);
 
 GST_EXPORT
+void                 gst_video_encoder_set_qos_enabled (GstVideoEncoder * encoder, gboolean enabled);
+
+GST_EXPORT
+gboolean             gst_video_encoder_is_qos_enabled (GstVideoEncoder * encoder);
+
+GST_EXPORT
 GstClockTimeDiff     gst_video_encoder_get_max_encode_time (GstVideoEncoder *encoder, GstVideoCodecFrame * frame);
 
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
index c9b48d2..2faa28a 100644 (file)
@@ -552,6 +552,8 @@ GST_START_TEST (videoencoder_qos)
 
   setup_videoencodertester ();
 
+  gst_video_encoder_set_qos_enabled (GST_VIDEO_ENCODER (enc), TRUE);
+
   gst_pad_set_active (mysrcpad, TRUE);
   gst_element_set_state (enc, GST_STATE_PLAYING);
   gst_pad_set_active (mysinkpad, TRUE);