From 7950a4614c7dce57c7505503ba3d78495f9344c4 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 25 Oct 2017 11:41:02 +0200 Subject: [PATCH] videoencoder: add qos property 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 | 105 +++++++++++++++++++++++++++ gst-libs/gst/video/gstvideoencoder.h | 6 ++ tests/check/libs/videoencoder.c | 2 + 3 files changed, 113 insertions(+) diff --git a/gst-libs/gst/video/gstvideoencoder.c b/gst-libs/gst/video/gstvideoencoder.c index 03c76b9b37..f87257292f 100644 --- a/gst-libs/gst/video/gstvideoencoder.c +++ b/gst-libs/gst/video/gstvideoencoder.c @@ -79,6 +79,13 @@ * * 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 */ @@ -273,6 +292,38 @@ gst_video_encoder_get_type (void) return type; } +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) { @@ -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, ×tamp); 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; +} diff --git a/gst-libs/gst/video/gstvideoencoder.h b/gst-libs/gst/video/gstvideoencoder.h index 25bd877ac2..18b1ba52ff 100644 --- a/gst-libs/gst/video/gstvideoencoder.h +++ b/gst-libs/gst/video/gstvideoencoder.h @@ -368,6 +368,12 @@ void gst_video_encoder_get_allocator (GstVideoEncoder *encoder, 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); diff --git a/tests/check/libs/videoencoder.c b/tests/check/libs/videoencoder.c index c9b48d277c..2faa28a84a 100644 --- a/tests/check/libs/videoencoder.c +++ b/tests/check/libs/videoencoder.c @@ -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);