mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
videoencoder: Add min-force-key-unit-interval property
This allows configuring the minimum interval between subsequent force-key-unit requests and prevents a big bitrate increase if a lot of key-units are requested. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/684>
This commit is contained in:
parent
931b5ad996
commit
c5b081edc2
2 changed files with 109 additions and 4 deletions
|
@ -113,11 +113,13 @@ GST_DEBUG_CATEGORY (videoencoder_debug);
|
||||||
/* properties */
|
/* properties */
|
||||||
|
|
||||||
#define DEFAULT_QOS FALSE
|
#define DEFAULT_QOS FALSE
|
||||||
|
#define DEFAULT_MIN_FORCE_KEY_UNIT_INTERVAL 0
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_QOS,
|
PROP_QOS,
|
||||||
|
PROP_MIN_FORCE_KEY_UNIT_INTERVAL,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -139,6 +141,8 @@ struct _GstVideoEncoderPrivate
|
||||||
gboolean new_headers; /* Whether new headers were just set */
|
gboolean new_headers; /* Whether new headers were just set */
|
||||||
|
|
||||||
GQueue force_key_unit; /* List of pending forced keyunits */
|
GQueue force_key_unit; /* List of pending forced keyunits */
|
||||||
|
GstClockTime min_force_key_unit_interval;
|
||||||
|
GstClockTime last_force_key_unit_request;
|
||||||
|
|
||||||
guint32 system_frame_number;
|
guint32 system_frame_number;
|
||||||
|
|
||||||
|
@ -323,6 +327,10 @@ gst_video_encoder_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_QOS:
|
case PROP_QOS:
|
||||||
gst_video_encoder_set_qos_enabled (sink, g_value_get_boolean (value));
|
gst_video_encoder_set_qos_enabled (sink, g_value_get_boolean (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_MIN_FORCE_KEY_UNIT_INTERVAL:
|
||||||
|
gst_video_encoder_set_min_force_key_unit_interval (sink,
|
||||||
|
g_value_get_uint64 (value));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -339,6 +347,10 @@ gst_video_encoder_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_QOS:
|
case PROP_QOS:
|
||||||
g_value_set_boolean (value, gst_video_encoder_is_qos_enabled (sink));
|
g_value_set_boolean (value, gst_video_encoder_is_qos_enabled (sink));
|
||||||
break;
|
break;
|
||||||
|
case PROP_MIN_FORCE_KEY_UNIT_INTERVAL:
|
||||||
|
g_value_set_uint64 (value,
|
||||||
|
gst_video_encoder_get_min_force_key_unit_interval (sink));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -382,6 +394,22 @@ gst_video_encoder_class_init (GstVideoEncoderClass * klass)
|
||||||
g_param_spec_boolean ("qos", "Qos",
|
g_param_spec_boolean ("qos", "Qos",
|
||||||
"Handle Quality-of-Service events from downstream", DEFAULT_QOS,
|
"Handle Quality-of-Service events from downstream", DEFAULT_QOS,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstVideoEncoder:min-force-key-unit-interval:
|
||||||
|
*
|
||||||
|
* Minimum interval between force-keyunit requests in nanoseconds. See
|
||||||
|
* gst_video_encoder_set_min_force_key_unit_interval() for more details.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
**/
|
||||||
|
g_object_class_install_property (gobject_class,
|
||||||
|
PROP_MIN_FORCE_KEY_UNIT_INTERVAL,
|
||||||
|
g_param_spec_uint64 ("min-force-key-unit-interval",
|
||||||
|
"Minimum Force Keyunit Interval",
|
||||||
|
"Minimum interval between force-keyunit requests in nanoseconds", 0,
|
||||||
|
G_MAXUINT64, DEFAULT_MIN_FORCE_KEY_UNIT_INTERVAL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static GList *
|
static GList *
|
||||||
|
@ -427,6 +455,7 @@ gst_video_encoder_reset (GstVideoEncoder * encoder, gboolean hard)
|
||||||
|
|
||||||
g_queue_clear_full (&priv->force_key_unit,
|
g_queue_clear_full (&priv->force_key_unit,
|
||||||
(GDestroyNotify) forced_key_unit_event_free);
|
(GDestroyNotify) forced_key_unit_event_free);
|
||||||
|
priv->last_force_key_unit_request = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
priv->drained = TRUE;
|
priv->drained = TRUE;
|
||||||
|
|
||||||
|
@ -1527,15 +1556,23 @@ gst_video_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
GST_OBJECT_LOCK (encoder);
|
GST_OBJECT_LOCK (encoder);
|
||||||
if (priv->force_key_unit.head) {
|
if (priv->force_key_unit.head) {
|
||||||
GstClockTime running_time;
|
|
||||||
GList *l;
|
GList *l;
|
||||||
|
GstClockTime running_time;
|
||||||
|
gboolean throttled = FALSE, have_fevt = FALSE;
|
||||||
GQueue matching_fevt = G_QUEUE_INIT;
|
GQueue matching_fevt = G_QUEUE_INIT;
|
||||||
|
|
||||||
running_time =
|
running_time =
|
||||||
gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
|
gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
|
||||||
cstart);
|
cstart);
|
||||||
|
|
||||||
for (l = priv->force_key_unit.head; l; l = l->next) {
|
throttled = (priv->min_force_key_unit_interval != 0 &&
|
||||||
|
priv->min_force_key_unit_interval != GST_CLOCK_TIME_NONE &&
|
||||||
|
priv->last_force_key_unit_request != GST_CLOCK_TIME_NONE &&
|
||||||
|
priv->last_force_key_unit_request + priv->min_force_key_unit_interval >
|
||||||
|
running_time);
|
||||||
|
|
||||||
|
for (l = priv->force_key_unit.head; l && (!throttled || !have_fevt);
|
||||||
|
l = l->next) {
|
||||||
ForcedKeyUnitEvent *fevt = l->data;
|
ForcedKeyUnitEvent *fevt = l->data;
|
||||||
|
|
||||||
/* Skip pending keyunits */
|
/* Skip pending keyunits */
|
||||||
|
@ -1544,12 +1581,16 @@ gst_video_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
/* Simple case, keyunit ASAP */
|
/* Simple case, keyunit ASAP */
|
||||||
if (fevt->running_time == GST_CLOCK_TIME_NONE) {
|
if (fevt->running_time == GST_CLOCK_TIME_NONE) {
|
||||||
|
have_fevt = TRUE;
|
||||||
|
if (!throttled)
|
||||||
g_queue_push_tail (&matching_fevt, fevt);
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Event for before this frame */
|
/* Event for before this frame */
|
||||||
if (fevt->running_time <= running_time) {
|
if (fevt->running_time <= running_time) {
|
||||||
|
have_fevt = TRUE;
|
||||||
|
if (!throttled)
|
||||||
g_queue_push_tail (&matching_fevt, fevt);
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1558,6 +1599,16 @@ gst_video_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (throttled && have_fevt) {
|
||||||
|
GST_DEBUG_OBJECT (encoder,
|
||||||
|
"Not requesting a new key unit yet due to throttling (%"
|
||||||
|
GST_TIME_FORMAT " + %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (priv->last_force_key_unit_request),
|
||||||
|
GST_TIME_ARGS (priv->min_force_key_unit_interval),
|
||||||
|
GST_TIME_ARGS (running_time));
|
||||||
|
g_queue_clear (&matching_fevt);
|
||||||
|
}
|
||||||
|
|
||||||
if (matching_fevt.length > 0) {
|
if (matching_fevt.length > 0) {
|
||||||
ForcedKeyUnitEvent *fevt;
|
ForcedKeyUnitEvent *fevt;
|
||||||
gboolean all_headers = FALSE;
|
gboolean all_headers = FALSE;
|
||||||
|
@ -1576,6 +1627,7 @@ gst_video_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME (frame);
|
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME (frame);
|
||||||
if (all_headers)
|
if (all_headers)
|
||||||
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME_HEADERS (frame);
|
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME_HEADERS (frame);
|
||||||
|
priv->last_force_key_unit_request = running_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GST_OBJECT_UNLOCK (encoder);
|
GST_OBJECT_UNLOCK (encoder);
|
||||||
|
@ -3004,3 +3056,50 @@ gst_video_encoder_is_qos_enabled (GstVideoEncoder * encoder)
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_video_encoder_set_min_force_key_unit_interval:
|
||||||
|
* @encoder: the encoder
|
||||||
|
* @interval: minimum interval
|
||||||
|
*
|
||||||
|
* Sets the minimum interval for requesting keyframes based on force-keyunit
|
||||||
|
* events. Setting this to 0 will allow to handle every event, setting this to
|
||||||
|
* %GST_CLOCK_TIME_NONE causes force-keyunit events to be ignored.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_video_encoder_set_min_force_key_unit_interval (GstVideoEncoder * encoder,
|
||||||
|
GstClockTime interval)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_VIDEO_ENCODER (encoder));
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (encoder);
|
||||||
|
encoder->priv->min_force_key_unit_interval = interval;
|
||||||
|
GST_OBJECT_UNLOCK (encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_video_encoder_get_min_force_key_unit_interval:
|
||||||
|
* @encoder: the encoder
|
||||||
|
*
|
||||||
|
* Returns the minimum force-keyunit interval, see gst_video_encoder_set_min_force_key_unit_interval()
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Returns: the minimum force-keyunit interval
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
GstClockTime
|
||||||
|
gst_video_encoder_get_min_force_key_unit_interval (GstVideoEncoder * encoder)
|
||||||
|
{
|
||||||
|
GstClockTime interval;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_VIDEO_ENCODER (encoder), GST_CLOCK_TIME_NONE);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (encoder);
|
||||||
|
interval = encoder->priv->min_force_key_unit_interval;
|
||||||
|
GST_OBJECT_UNLOCK (encoder);
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
|
@ -381,6 +381,12 @@ gboolean gst_video_encoder_is_qos_enabled (GstVideoEncoder * encoder
|
||||||
GST_VIDEO_API
|
GST_VIDEO_API
|
||||||
GstClockTimeDiff gst_video_encoder_get_max_encode_time (GstVideoEncoder *encoder, GstVideoCodecFrame * frame);
|
GstClockTimeDiff gst_video_encoder_get_max_encode_time (GstVideoEncoder *encoder, GstVideoCodecFrame * frame);
|
||||||
|
|
||||||
|
GST_VIDEO_API
|
||||||
|
void gst_video_encoder_set_min_force_key_unit_interval (GstVideoEncoder * encoder,
|
||||||
|
GstClockTime interval);
|
||||||
|
GST_VIDEO_API
|
||||||
|
GstClockTime gst_video_encoder_get_min_force_key_unit_interval (GstVideoEncoder * encoder);
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVideoEncoder, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVideoEncoder, gst_object_unref)
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
Loading…
Reference in a new issue