From 59229b20a5965081a210296122efe34e71d9d79f Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Fri, 10 Jan 2014 13:23:48 +0100 Subject: [PATCH] encoder: add keyframe period API. Add gst_vaapi_encoder_set_keyframe_period() interface to allow the user control the maximum distance between two keyframes. This new property can only be set prior to gst_vaapi_encoder_set_codec_state(). A value of zero for "keyframe-period" gets it re-evaluated to the actual framerate during encoder reconfiguration. --- gst-libs/gst/vaapi/gstvaapiencoder.c | 57 +++++++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiencoder.h | 7 +++ gst-libs/gst/vaapi/gstvaapiencoder_h264.c | 31 ++++---------- gst-libs/gst/vaapi/gstvaapiencoder_h264.h | 11 ++--- gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h | 3 -- gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c | 21 +++------ gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h | 5 +-- gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h | 4 -- gst-libs/gst/vaapi/gstvaapiencoder_priv.h | 12 ++++++ 9 files changed, 94 insertions(+), 57 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.c b/gst-libs/gst/vaapi/gstvaapiencoder.c index d629da1..f222361 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder.c @@ -139,6 +139,18 @@ gst_vaapi_encoder_properties_get_default (const GstVaapiEncoderClass * klass) "The desired bitrate expressed in kbps (0: auto-calculate)", 0, 100 * 1024, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstVaapiEncoder:keyframe-period: + * + * The maximal distance between two keyframes. + */ + GST_VAAPI_ENCODER_PROPERTIES_APPEND (props, + GST_VAAPI_ENCODER_PROP_KEYFRAME_PERIOD, + g_param_spec_uint ("keyframe-period", + "Keyframe Period", + "Maximal distance between two keyframes (0: auto-calculate)", 1, 300, + 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + return props; } @@ -478,10 +490,15 @@ static GstVaapiEncoderStatus gst_vaapi_encoder_reconfigure_internal (GstVaapiEncoder * encoder) { GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder); + GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder); GstVaapiEncoderStatus status; GstVaapiVideoPool *pool; guint codedbuf_size; + /* Generate a keyframe every second */ + if (!encoder->keyframe_period) + encoder->keyframe_period = (vip->fps_n + vip->fps_d - 1) / vip->fps_d; + status = klass->reconfigure (encoder); if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) return status; @@ -603,6 +620,10 @@ set_property (GstVaapiEncoder * encoder, gint prop_id, const GValue * value) status = gst_vaapi_encoder_set_bitrate (encoder, g_value_get_uint (value)); break; + case GST_VAAPI_ENCODER_PROP_KEYFRAME_PERIOD: + status = gst_vaapi_encoder_set_keyframe_period (encoder, + g_value_get_uint (value)); + break; } return status; @@ -782,6 +803,42 @@ error_operation_failed: } } +/** + * gst_vaapi_encoder_set_keyframe_period: + * @encoder: a #GstVaapiEncoder + * @keyframe_period: the maximal distance between two keyframes + * + * Notifies the @encoder to use the supplied @keyframe_period value. + * + * Note: currently, the keyframe period can only be specified before + * the last call to gst_vaapi_encoder_set_codec_state(), which shall + * occur before the first frame is encoded. Afterwards, any change to + * this parameter causes gst_vaapi_encoder_set_keyframe_period() to + * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED. + * + * Return value: a #GstVaapiEncoderStatus + */ +GstVaapiEncoderStatus +gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder, + guint keyframe_period) +{ + g_return_val_if_fail (encoder != NULL, 0); + + if (encoder->keyframe_period != keyframe_period + && encoder->num_codedbuf_queued > 0) + goto error_operation_failed; + + encoder->keyframe_period = keyframe_period; + return GST_VAAPI_ENCODER_STATUS_SUCCESS; + + /* ERRORS */ +error_operation_failed: + { + GST_ERROR ("could not change keyframe period after encoding started"); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } +} + /* Initialize default values for configurable properties */ static gboolean gst_vaapi_encoder_init_properties (GstVaapiEncoder * encoder) diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.h b/gst-libs/gst/vaapi/gstvaapiencoder.h index 8f6e6ae..1c3c86b 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder.h @@ -72,12 +72,15 @@ typedef enum * GstVaapiEncoderProp: * @GST_VAAPI_ENCODER_PROP_RATECONTROL: Rate control (#GstVaapiRateControl). * @GST_VAAPI_ENCODER_PROP_BITRATE: Bitrate expressed in kbps (uint). + * @GST_VAAPI_ENCODER_PROP_KEYFRAME_PERIOD: The maximal distance + * between two keyframes (uint). * * The set of configurable properties for the encoder. */ typedef enum { GST_VAAPI_ENCODER_PROP_RATECONTROL = 1, GST_VAAPI_ENCODER_PROP_BITRATE, + GST_VAAPI_ENCODER_PROP_KEYFRAME_PERIOD, } GstVaapiEncoderProp; /** @@ -126,6 +129,10 @@ gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder, GstVideoCodecFrame * frame); GstVaapiEncoderStatus +gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder, + guint keyframe_period); + +GstVaapiEncoderStatus gst_vaapi_encoder_get_buffer_with_timeout (GstVaapiEncoder * encoder, GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr, guint64 timeout); diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c index ad79f7c..4cd1021 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c @@ -854,7 +854,7 @@ fill_va_sequence_param (GstVaapiEncoderH264 * encoder, memset (seq, 0, sizeof (VAEncSequenceParameterBufferH264)); seq->seq_parameter_set_id = 0; seq->level_idc = encoder->level; - seq->intra_period = encoder->intra_period; + seq->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder); seq->ip_period = 0; // ? if (base_encoder->bitrate > 0) seq->bits_per_second = base_encoder->bitrate * 1024; @@ -1284,13 +1284,11 @@ ensure_bitrate (GstVaapiEncoderH264 * encoder) static void reset_properties (GstVaapiEncoderH264 * encoder) { + GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder); guint width_mbs, height_mbs, total_mbs; - if (encoder->intra_period > GST_VAAPI_ENCODER_H264_MAX_INTRA_PERIOD) - encoder->intra_period = GST_VAAPI_ENCODER_H264_MAX_INTRA_PERIOD; - - if (encoder->idr_period < encoder->intra_period) - encoder->idr_period = encoder->intra_period; + if (encoder->idr_period < base_encoder->keyframe_period) + encoder->idr_period = base_encoder->keyframe_period; if (encoder->idr_period > GST_VAAPI_ENCODER_H264_MAX_IDR_PERIOD) encoder->idr_period = GST_VAAPI_ENCODER_H264_MAX_IDR_PERIOD; @@ -1307,8 +1305,8 @@ reset_properties (GstVaapiEncoderH264 * encoder) encoder->slice_num = (total_mbs + 1) / 2; g_assert (encoder->slice_num); - if (encoder->b_frame_num > (encoder->intra_period + 1) / 2) - encoder->b_frame_num = (encoder->intra_period + 1) / 2; + if (encoder->b_frame_num > (base_encoder->keyframe_period + 1) / 2) + encoder->b_frame_num = (base_encoder->keyframe_period + 1) / 2; if (encoder->b_frame_num > 50) encoder->b_frame_num = 50; @@ -1522,7 +1520,8 @@ gst_vaapi_encoder_h264_reordering (GstVaapiEncoder * base, /* check key frames */ if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) || - (encoder->frame_index % encoder->intra_period) == 0) { + (encoder->frame_index % GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == + 0) { ++encoder->cur_frame_num; ++encoder->frame_index; @@ -1710,9 +1709,6 @@ gst_vaapi_encoder_h264_set_property (GstVaapiEncoder * base_encoder, GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder); switch (prop_id) { - case GST_VAAPI_ENCODER_H264_PROP_KEY_PERIOD: - encoder->intra_period = g_value_get_uint (value); - break; case GST_VAAPI_ENCODER_H264_PROP_MAX_BFRAMES: encoder->b_frame_num = g_value_get_uint (value); break; @@ -1772,17 +1768,6 @@ gst_vaapi_encoder_h264_get_default_properties (void) return NULL; /** - * GstVaapiEncoderH264:key-period - * - * The maximal distance between two keyframes. - */ - GST_VAAPI_ENCODER_PROPERTIES_APPEND (props, - GST_VAAPI_ENCODER_H264_PROP_KEY_PERIOD, - g_param_spec_uint ("key-period", - "Key Period", "Maximal distance between two key-frames", 1, 300, 30, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** * GstVaapiEncoderH264:max-bframes: * * The number of B-frames between I and P. diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.h b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h index b6c4a1c..9b3eb49 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h @@ -30,8 +30,6 @@ typedef struct _GstVaapiEncoderH264 GstVaapiEncoderH264; /** * GstVaapiEncoderH264Prop: - * @GST_VAAPI_ENCODER_H264_PROP_KEY_PERIOD: Maximal distance between two - * keyframes (uint). * @GST_VAAPI_ENCODER_H264_PROP_MAX_BFRAMES: Number of B-frames between I * and P (uint). * @GST_VAAPI_ENCODER_H264_PROP_INIT_QP: Initial quantizer value (uint). @@ -41,11 +39,10 @@ typedef struct _GstVaapiEncoderH264 GstVaapiEncoderH264; * The set of H.264 encoder specific configurable properties. */ typedef enum { - GST_VAAPI_ENCODER_H264_PROP_KEY_PERIOD = -1, - GST_VAAPI_ENCODER_H264_PROP_MAX_BFRAMES = -2, - GST_VAAPI_ENCODER_H264_PROP_INIT_QP = -3, - GST_VAAPI_ENCODER_H264_PROP_MIN_QP = -4, - GST_VAAPI_ENCODER_H264_PROP_NUM_SLICES = -5, + GST_VAAPI_ENCODER_H264_PROP_MAX_BFRAMES = -1, + GST_VAAPI_ENCODER_H264_PROP_INIT_QP = -2, + GST_VAAPI_ENCODER_H264_PROP_MIN_QP = -3, + GST_VAAPI_ENCODER_H264_PROP_NUM_SLICES = -4, } GstVaapiEncoderH264Prop; GstVaapiEncoder * diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h index fd4cd29..f2b3a8e 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h @@ -57,8 +57,6 @@ typedef enum #define GST_VAAPI_ENCODER_H264_DEFAULT_LEVEL GST_VAAPI_ENCODER_H264_LEVEL_31 #define GST_VAAPI_ENCODER_H264_DEFAULT_INIT_QP 26 #define GST_VAAPI_ENCODER_H264_DEFAULT_MIN_QP 1 -#define GST_VAAPI_ENCODER_H264_DEFAULT_INTRA_PERIOD 30 -#define GST_VAAPI_ENCODER_H264_MAX_INTRA_PERIOD 512 #define GST_VAAPI_ENCODER_H264_MAX_IDR_PERIOD 512 #define GST_VAAPI_ENCODER_H264_DEFAULT_SLICE_NUM 1 @@ -70,7 +68,6 @@ struct _GstVaapiEncoderH264 /* public */ guint32 profile; guint32 level; - guint32 intra_period; guint32 idr_period; guint32 init_qp; /*default 24 */ guint32 min_qp; /*default 1 */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c index 1c9f6a2..7b88128 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c @@ -177,7 +177,7 @@ fill_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncSequence * sequence) memset (seq, 0, sizeof (VAEncSequenceParameterBufferMPEG2)); - seq->intra_period = encoder->intra_period; + seq->intra_period = base_encoder->keyframe_period; seq->ip_period = encoder->ip_period; seq->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder); seq->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder); @@ -587,7 +587,7 @@ gst_vaapi_encoder_mpeg2_reordering (GstVaapiEncoder * base, return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED; } - if (encoder->frame_num >= encoder->intra_period) { + if (encoder->frame_num >= base->keyframe_period) { encoder->frame_num = 0; clear_references (encoder); } @@ -598,7 +598,7 @@ gst_vaapi_encoder_mpeg2_reordering (GstVaapiEncoder * base, } else { encoder->new_gop = FALSE; if ((encoder->frame_num % (encoder->ip_period + 1)) == 0 || - encoder->frame_num == encoder->intra_period - 1) { + encoder->frame_num == base->keyframe_period - 1) { picture->type = GST_VAAPI_PICTURE_TYPE_P; encoder->dump_frames = TRUE; } else { @@ -680,8 +680,8 @@ gst_vaapi_encoder_mpeg2_reconfigure (GstVaapiEncoder * base_encoder) GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder); - if (encoder->ip_period > encoder->intra_period) { - encoder->ip_period = encoder->intra_period - 1; + if (encoder->ip_period > base_encoder->keyframe_period) { + encoder->ip_period = base_encoder->keyframe_period - 1; } if (!ensure_profile_and_level (encoder)) @@ -771,9 +771,6 @@ gst_vaapi_encoder_mpeg2_set_property (GstVaapiEncoder * base_encoder, case GST_VAAPI_ENCODER_MPEG2_PROP_QUANTIZER: encoder->cqp = g_value_get_uint (value); break; - case GST_VAAPI_ENCODER_MPEG2_PROP_KEY_PERIOD: - encoder->intra_period = g_value_get_uint (value); - break; case GST_VAAPI_ENCODER_MPEG2_PROP_MAX_BFRAMES: encoder->ip_period = g_value_get_uint (value); break; @@ -832,14 +829,6 @@ gst_vaapi_encoder_mpeg2_get_default_properties (void) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); GST_VAAPI_ENCODER_PROPERTIES_APPEND (props, - GST_VAAPI_ENCODER_MPEG2_PROP_KEY_PERIOD, - g_param_spec_uint ("key-period", - "Key Period", "Maximal distance between two key-frames", 1, - GST_VAAPI_ENCODER_MPEG2_MAX_GOP_SIZE, - GST_VAAPI_ENCODER_MPEG2_DEFAULT_GOP_SIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - GST_VAAPI_ENCODER_PROPERTIES_APPEND (props, GST_VAAPI_ENCODER_MPEG2_PROP_MAX_BFRAMES, g_param_spec_uint ("max-bframes", "Max B-Frames", "Number of B-frames between I and P", 0, diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h index bd6d1a7..e4a547d 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h @@ -31,8 +31,6 @@ typedef struct _GstVaapiEncoderMpeg2 GstVaapiEncoderMpeg2; /** * GstVaapiEncoderMpeg2Prop: * @GST_VAAPI_ENCODER_MPEG2_PROP_QUANTIZER: Constant quantizer value (uint). - * @GST_VAAPI_ENCODER_MPEG2_PROP_KEY_PERIOD: Maximal distance between two - * keyframes (uint). * @GST_VAAPI_ENCODER_MPEG2_PROP_MAX_BFRAMES: Number of B-frames between I * and P (uint). * @@ -40,8 +38,7 @@ typedef struct _GstVaapiEncoderMpeg2 GstVaapiEncoderMpeg2; */ typedef enum { GST_VAAPI_ENCODER_MPEG2_PROP_QUANTIZER = -1, - GST_VAAPI_ENCODER_MPEG2_PROP_KEY_PERIOD = -2, - GST_VAAPI_ENCODER_MPEG2_PROP_MAX_BFRAMES = -3, + GST_VAAPI_ENCODER_MPEG2_PROP_MAX_BFRAMES = -2, } GstVaapiEncoderMpeg2Prop; GstVaapiEncoder * diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h index df94ab6..b3159bd 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h @@ -53,9 +53,6 @@ typedef enum #define GST_VAAPI_ENCODER_MPEG2_MAX_CQP 62 #define GST_VAAPI_ENCODER_MPEG2_DEFAULT_CQP 8 -#define GST_VAAPI_ENCODER_MPEG2_MAX_GOP_SIZE 512 -#define GST_VAAPI_ENCODER_MPEG2_DEFAULT_GOP_SIZE 30 - #define GST_VAAPI_ENCODER_MPEG2_MAX_MAX_BFRAMES 16 #define GST_VAAPI_ENCODER_MPEG2_DEFAULT_MAX_BFRAMES 2 @@ -81,7 +78,6 @@ struct _GstVaapiEncoderMpeg2 guint32 profile; guint32 level; guint32 cqp; - guint32 intra_period; guint32 ip_period; /* re-ordering */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h index c469deb..d473a05 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_priv.h @@ -121,6 +121,17 @@ G_BEGIN_DECLS #define GST_VAAPI_ENCODER_RATE_CONTROL(encoder) \ (GST_VAAPI_ENCODER_CAST (encoder)->rate_control) +/** + * GST_VAAPI_ENCODER_KEYFRAME_PERIOD: + * @encoder: a #GstVaapiEncoder + * + * Macro that evaluates to the keyframe period. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_ENCODER_KEYFRAME_PERIOD +#define GST_VAAPI_ENCODER_KEYFRAME_PERIOD(encoder) \ + (GST_VAAPI_ENCODER_CAST (encoder)->keyframe_period) + #define GST_VAAPI_ENCODER_CHECK_STATUS(exp, err_num, err_reason, ...) \ if (!(exp)) { \ ret = err_num; \ @@ -170,6 +181,7 @@ struct _GstVaapiEncoder GstVaapiRateControl rate_control; guint32 rate_control_mask; guint bitrate; /* kbps */ + guint keyframe_period; GMutex mutex; GCond surface_free; -- 2.7.4